C++关键字decltype
decltype
引入的原因之一是在函数模板中遇到如下情形:
template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
?type? tmp = a + b;
}
此时,tmp类型该定义为哪种呢?我们知道基础数据类型相加时会自动进行类型提升,直接用T1或者T2都是不合适的。此时就需要使用新的关键字decltype
。
template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
decltype(a + b) tmp = a + b;
}
由编译器自己在编译过程中推导,当然也可以用auto代替。decltype
关键字的作用是获取提供给它的参数的数据类型。可以是变量,表达式,函数调用等。使用decltype
的格式如下:
decltype(expression) var;
确定decltype推导出来的类型按如下步骤:
-
第一步:如果expression是一个没有额外括号扩起来的变量,则var的类型和该变量类型相同,包括cv限定符;
int x; int y; int z[10]; int &rx = x; const int *pi; decltype(x) a; //int类型 decltype(rx) b = y; //int &类型 decltype(pi) c; //const int* 类型 decltype(z) d; //int[10]类型 //除了一般变量,也可以是函数指针(起始也是一般变量,就是指针而已) int foo(){return 0;} decltype(foo) myFoo; //int(*)()类型,注意这里表达式是函数名
-
第二步:如果expression是函数调用,则var的类型和函数返回值一样;
int foo(){return 0;} decltype(foo()) fooRet; //int类型
处理函数调用时,它的原理是直接查看函数声明中的返回值类型,所以甚至都不需要看到函数实现:
int foo(); int main() { decltype(foo()) var; //int类型 return 0; }
-
第三步:如果expression是用额外括号括起来的左值,那么var的类型就是对应类型的引用,包括cv限定符;
int x; int y; const int a = 1; const int b = 2; decltype((x)) ry = y; //int &类型,如果不做赋值操作,会提示错误 decltype((a)) rb = b; //const int &类型,如果不做赋值操作,会提示错误 rb = 1; //报错,因为rb是const int &类型
-
第四步:如果expression是表达式,则var类型与其类型一样:
int x = 1; int &y = x; decltype(x + 1) a; //int类型 decltype(x + y) b; //int类型 decltype(3) c; //int类型 decltype(4L) d; //long类型 decltype(5.0f) e; //float类型 int foo(); decltype(foo() + 3) f; //int类型
有一个比较特殊的类型
void
类型,我们知道void类型用在函数声明上,主要给函数返回值或者参数用。所以有以下变态写法:void foo(); decltype(foo()) bar(decltype(foo())) { }
不过这种用法好像毫无意义。
还有一种情况,如下:
template <typename T1, typename T2>
?type? Add(T1 a, T2 b)
{
return a + b;
}
如果定义了一个模板函数,将两个不同类型的变量相加,并且返回他们的和。那此时返回值类型该是那种?或许我可以加入第三个类型解决:
template <typename T0, typename T1, typename T2>
T0 Add(T1 a, T2 b)
{
return a + b;
}
如果调用如下:
char a = 1;
short b = 2;
int sum;
sum = Add<int, char, short>(a, b);
sum = Add(a, b); //不支持类型推导,提示无法推导类型T0
好像也没啥问题,但是需要我们知道不同类型相加时类型提升的规则,这无疑是很麻烦的。于是decltype
被引入了,它结合auto
关键字使用:
template <typename T1, typename T2>
auto Add(T1 a, T2 b) -> decltype(a + b)
{
return a + b;
}
auto function(args...) -> type
这种函数声明时,以auto作为返回值类型,真实类型放后面通过->
连接的语法称之为后置返回类型
。其中auto表示占位符,表示后置返回类型提供的类型,这是C++11给auto新增的一种作用。这种用法也可以用于一般函数的定义。
auto foo() -> int
{
}