decltype
The keyword decltype in C++, returns the data type of an expression or variable. This keyword works for any type, built-in or user-defined. Following example illustrates this behavior.
#include <iostream> //main header
using namespace std; //namespace
class MFPoint
{
};
int main()
{
int ia; //Built-in type
cout << typeid(decltype(ia)).name() << endl;
double db; //Built-in type
cout << typeid(decltype(db)).name() << endl;
MFPoint mfp; //User-defined type
cout << typeid(decltype(mfp)).name() << endl;
return 0;
}
The output is:
i
d
7MFPoint
Reference type information
The decltype also returns the information regarding reference. For instance, if the given input is a variable of type L-value reference, then decltype takes care of this. Following example, illustrates this with a normal variables and with both an L-value and and R-value reference.
#include <iostream> //main header
using namespace std; //namespace
class MFPoint
{
};
int main()
{
int ia0; //Not reference variable
if(std::is_reference<decltype(ia0)>() )
cout << "Reference" << endl;
else
cout << "No reference" << endl;
int &ia = ia0; //L-value reference
if(std::is_reference<decltype(ia)>() )
cout << "Reference" << endl;
else
cout << "No reference" << endl;
double &&db=1.1; //R-value reference
if(std::is_reference<decltype(db)>() )
cout << "Reference" << endl;
else
cout << "No reference" << endl;
MFPoint mfp0;
MFPoint &mfp = mfp0;
if(std::is_reference<decltype(mfp)>() )
cout << "Reference" << endl;
else
cout << "No reference" << endl;
return 0;
}
Output
No reference
Reference
Reference
Reference
Additionally, the following program verifies that decltype is returning L-value and R-value reference information.
#include <iostream> //main header
using namespace std; //namespace
int main()
{
int ia0;
if( std::is_reference<decltype(ia0)>() )
cout << "Reference" << endl;
else
cout << "No Reference" << endl;
int &ia = ia0;
if( std::is_reference<decltype(ia)>() )
{
if(std::is_rvalue_reference<decltype(ia)>() )
cout << "R-value Reference" << endl;
else
cout << "L-rvalue Reference" << endl;
}
double &&db=1.1;
if( std::is_reference<decltype(db)>() )
{
if(std::is_rvalue_reference<decltype(db)>() )
cout << "R-value Reference" << endl;
else
cout << "L-rvalue Reference" << endl;
}
return 0;
}
Output is as follows:
No Reference
L-rvalue Reference
R-value Reference
auto return type without trailing return type
In C++11, the main use of decltype is for the declaration of functions where function return type is auto. Therefore, in such cases, a trailing return type expressions guide the compiler to deduce the return type. For this reason, in the absence of a trailing type, the compiler shall generate error.
For instance, in the following example, there is no trailing return type for function “getValue”.
#include <iostream> //main header
using namespace std; //namespace
auto getValue(int ix)
{
int iy = ix;
return iy;
}
int main()
{
return 0;
}
The output from compiler is:
Following code show, how to add a trailing return type. Generally, the trailing type uses the type of parameters. In particular, this is very much useful in template functions.
auto getValue(int ix) -> decltype(ix)
{
int iy = ix;
return iy;
}
If the trailing return type expression is constructed using some variable which is not a parameter, then the compiler shall generate error. For example, in this code, the variable iy is inside in the function scope but not in parameters.
auto getValue(int ix) -> decltype(iy)
{
int iy = ix;
return iy;
}
Constructing trailing return type for template functions
#include <iostream> //main header
using namespace std; //namespace
template<typename T>
auto getValue(T ix) -> decltype(ix)
{
T iy = ix;
return iy;
}
int main()
{
getValue(4);
return 0;
}
Use in variable definition
Since, the decltype returns actual datatype of variable, therefore, such datatype can be used to define a variable.
The following example illustrates this:
#include <iostream> //main header
using namespace std; //namespace
int main()
{
int ix = 9;
auto iy = ix;
decltype(ix) x1; //x1 is int
decltype(iy) y1; //y1 is int
cout << typeid(x1).name() << endl;
cout << typeid(y1).name() << endl;
return 0;
}
The output clearly shows both x1 and y1 become “int” type variable.
i
i
decltype for L-value expressions
When we use decltype with complicated L-value expressions, the this returns L-value types. For example, decltype(x) is int, whereas, when this the name x is wrapped in parenthesis, (x), then it becomes an L-value expression. Therefore, now decltype((x)) shall return int&.
#include <iostream> //main header
using namespace std; //namespace
int main()
{
int iy;
decltype(iy) iz = 8; // iy is int
decltype((iy)) ik = iz; // (iy) is int&
if(std::is_reference<decltype(iz)>())
cout << "Reference" << endl;
else
cout << "No Reference" << endl;
if(std::is_reference<decltype(ik)>())
cout << "Reference" << endl;
else
cout << "No Reference" << endl;
return 0;
}
Output:
No Reference
Reference