C++ Reactive Programming
上QQ阅读APP看书,第一时间看更新

Type deduction and inference

The Modern C++ language compiler does a wonderful job of deducing types from the expressions and statements specified by the programmers. Most modern programming languages do have support for type inference and so does Modern C++. This is an idiom borrowed from Functional Programming languages such as Haskell and ML. Type inferences are already available with the C# and Scala programming languages. We will write a small program to kick-start us with type inference:

//----- AutoFirst.cpp
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<string> vt = {"first", "second", "third", "fourth"};
//--- Explicitly specify the Type ( makes it verbose)
for (vector<string>::iterator it = vt.begin();
it != vt.end(); ++it)
cout << *it << " ";
//--- Let the compiler infer the type for us
for (auto it2 = vt.begin(); it2 != vt.end(); ++it2)
cout << *it2 << " ";
return 0;
}

The auto keyword specifies that the type of the variable will be deduced by the compiler based on initialization and the return values of functions specified in the expression. In this particular example, we do not gain much. As our declarations get more complicated, it is better to let the compiler do the type inference. Our code listings will use auto to simplify the code throughout the book. Now, let us write a simple program to make the idea even more clear:

//----- AutoSecond.cpp
#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;
int main() {
vector<double> vtdbl = {0, 3.14, 2.718, 10.00};
auto vt_dbl2 = vtdbl; // type will be deduced
auto size = vt_dbl2.size(); // size_t
auto &rvec = vtdbl; // specify a auto reference
cout << size << endl;
// Iterate - Compiler infers the type
for ( auto it = vtdbl.begin(); it != vtdbl.end(); ++it)
cout << *it << " ";
// 'it2' evaluates to iterator to vector of double
for (auto it2 = vt_dbl2.begin(); it2 != vt_dbl2.end(); ++it2)
cout << *it2 << " ";
// This will change the first element of vtdbl vector
rvec[0] = 100;
// Now Iterate to reflect the type
for ( auto it3 = vtdbl.begin(); it3 != vtdbl.end(); ++it3)
cout << *it3 << " ";
return 0;
}

The preceding code demonstrates the use of type inference while writing Modern C++ code. The C++ programming language also has a new keyword that helps to query the type of expression given as arguments. The general form of the keyword is decltype(<expr>). The following program helps to demonstrate the use of this particular keyword:

//---- Decltype.cpp
#include <iostream>
using namespace std;
int foo() { return 10; }
char bar() { return 'g'; }
auto fancy() -> decltype(1.0f) { return 1;} //return type is float
int main() {
// Data type of x is same as return type of foo()
// and type of y is same as return type of bar()
decltype(foo()) x;
decltype(bar()) y;
//--- in g++, Should print i => int
cout << typeid(x).name() << endl;
//--- in g++, Should print c => char
cout << typeid(y).name() << endl;
struct A { double x; };
const A* a = new A();
decltype(a->x) z; // type is double
decltype((a->x)) t= z; // type is const double&
//--- in g++, Should print d => double
cout << typeid(z).name() << endl;
cout << typeid(t).name() << endl;
//--- in g++, Should print f => float
cout << typeid(decltype(fancy())).name() << endl;
return 0;
}

The decltype is a compile-time construct and it helps to specify the type of a variable (the compiler will do the hard work to figure it out) and also helps us to force a type on a variable (see the preceding fancy() function).