1. example code
#include <typeinfo> #include <iostream> using namespace std; int main() { int i; decltype(i) j = 0; cout << typeid(j).name() << endl; float a; double b; decltype(a + b) c; cout << typeid(c).name() << endl; return 0; }
变量 j 的类型由decltype(i)进行声明,表示 j 的类型跟 i 相同(或者准确的说,是与 i 这个表达式返回的类型相同)。而类型c则跟(a+b)这个表达式返回的类型相同。decltype总是以一个普通的表达式为参数,返回该表达式的类型。decltype的类型推导在编译时进行。
2 与using结合使用
using size_t = decltype(sizeof(0)); using ptrdiff_t = decltype((int*)0 - (int*)0); using nullptr_t = decltype(nullptr);
sizt_t, ptrdiff_t, nullptr_t都是由decltype推导出类型。
3. 简化代码,匿名类型
#include<vector> using namespace std; int main() { vector<int> vec; typedef decltype(vec.begin()) vectype; for (vectype i = vec.begin(); i < vec.end(); i++) { //do something } for (decltype(vec)::iterator i = vec.begin(); i < vec.end(); i++) { //do something } }
enum class {K1, K2, K3} anon_e; union { decltype(anon_e) key; char* name; } anon_u; struct { int d; decltype(anon_u) id; } anon_s[100]; int main() { decltype(anon_s) as; as[0].id.key = decltype(anon_e)::K1; }
4. decltype推导四原则
(1)如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译时错误。
(2)否则,假设e的类型是T,如果e是一个将亡值(xvalue),那么decltype(e)为T&&。
(3)否则,假设e的类型是T,如果e是一个左值,则decltype(e)为T&。
(4)否则,假设e的类型是T,则decltype(e)为T。
标记表达式:所有除去关键字、字面量等编译器需要使用的标记之外的程序员自定义的标记都可以是标记符。而单个标记符对应的表达式就是标记符表达式。
如一下例子:
int i = 4; int arr[5] = {0}; int* ptr = arr; struct S { double d; } s; void Overloaded(int); void Overloaded(char); int && RvalRef(); const bool Func(int); //规则1:单个标记符表达式以及访问类成员,推导为本类型 decltype(arr) var1; //int[5],标记表达式 decltype(ptr) var2; //int*, 标记表达式 decltype(s.d) var4; //double,成员访问表达式 decltype(Overloaded) var5; //无法通过编译,是个重载的函数 //规则2:将亡值,推导为类型的右值引用 decltype(RvalRef()) var6 = 1; //int&& //规则3:左值,推导为类型的引用 decltype(true ? i : 1) var7 = i; //int&, 三元运算符,返回一个i的左值 decltype((i)) var8 = i; //int&, 带圆括号的左值 decltype(++i) var9 = i; //int&, ++i返回i的左值 decltype(arr[3]) var10 = 9; //int&, []操作返回左值 decltype(*ptr) var11 = 9; //int&, *操作返回左值 decltype("lval") var12 = "lval"; //const char(&)[9], 字符串字面常量为左值 //规则4:以上都不是,推导为本类型 delctype(1) var13; //int, 除字符串外字面常量为右值 decltype(i++) var14; //int, i++返回右值 decltype((Func(1))) var15; //const bool, 圆括号可以忽略
5.追踪返回类型
template<typename T1, typenameT2> auto Sum(T1 & t1, T2 & t2) -> decltype(t1 + t2) { return t1 + t2; }
追踪返回类型的函数和普通函数的声明最大的区别在于返回类型的后置。
比如:
//普通函数 int func(char* a, int b); //追踪返回类型 auto func(char* a, int b) -> int;
模板的类型推导,不使用具体的类型声明
#include <iostream> using namespace std; template<typename T1, typename T2> auto Sum(const T1 & t1, const T2 & t2) -> decltype(t1 + t2) { return t1 + t2; } template<typename T1, typename T2> auto Mul(const T1 & t1, const T2 & t2) -> decltype(t1 * t2) { return t1 * t2; } int main() { auto a = 3; auto b = 4L; auto pi = 3.14; auto c = Mul(Sum(a, b), pi); cout << c << endl; //21.98 return 0; }