decltype,编译时类型推导.
一 decltype推导四原则
1 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。
2 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T &&
3 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。
4 否则,假设e的类型是T,则decltype(e)为T。标记符: 指的是除去关键字、字面量等编译器需要使用的标记之外的程序员自己定义的标记,而单个标记符对应的表达式即为标记符表达式。
举例如下:
struct A {
double x;
};
int var;
A a;
const A a1 = {1};
const int&& f1();
int f2();
int f2(int a);
// 推导1 标记符表达式和类成员访问表达式,推导为其类型
decltype(1) i = 1; // int
decltype(var) i1 = 1; // int
decltype((var)) i2 = var; // 双括号 int&
decltype(a.x) x1 = 1; // double
decltype(a1) a11 = a1; // const A
//decltype(f2) f; // 重载函数,报错
// 推导2 将亡值,推导为右值引用
decltype(f1()) r1 = 1; // const int&&
// 推导3 左值,推导为类型的引用
decltype(++var) i3 = var; // int&
decltype("hello") str1 = "hello"; // const char(&)[6] 字符串字面值是常量左值
// 推导4 其他推导为其类型
decltype(f2()) r2; // int
decltype(var++) i4; // int
decltype(1) i5; // int
二 用法
1 与using / typedef合用,用于定义类型。
using B = decltype(a);
typedef decltype(a) C;
2 重用匿名类型
struct {
int x;
} s;
decltype(s) s1;
3 与auto结合使用
// C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u)) {
return forward<T>(t) + forward<U>(u);
};
// C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u) {
return forward<T>(t) + forward<U>(u);
};
三 与auto比较
1.auto忽略顶层const,decltype保留顶层const;
2.对引用操作,auto推断出原有类型,decltype推断出引用;
3.对解引用操作,auto推断出原有类型,decltype推断出引用;
4.auto推断时会实际执行,decltype不会执行,只做分析。
举例如下:
{
// 1
const int a = 0;
auto b = a; // int
decltype(a) bb = a; // const int
// 2
int a1 = 1;
int& b1 = a1;
auto c = b1; // int
decltype(b1) cc = b1; // int&
// 3
int* p = &a1;
auto p1 = *p; // int
decltype(*p) p2 = a1; // int&
// 4
cout << "before decltype a1: " << a1 << endl; // 1
decltype(a1++) a11 = 2; // 只分析,不计算
cout << "after decltype a1: " << a1 << endl; // 1
}
四 参考