decltype
有两种使用语法
decltype(entity)
, entity 可以是一个变量, 也可以是一个常量字符: 'a', 12, true, nullptr...,
decltype
将会根据entity
的type
来生成与其一致的type
.decltype(expression)
, expression 可以参考这里,decltype
将根据表达式的value category
属性来返回对应的type
.
如果表达式返回的值的类别是lvalue expression
, 那么decltype
将生成:T&
.
如果表达式返回的值的类别是xrvalue expression
, 那么decltype
将生成:T&&
.
如果表达式返回的值的类别是prvalue expression
, 那么decltype
将生成:T
.如果不熟悉
value category
, 请参考这里.
验证和测试办法
C++没有提供反射的机制, 无法直接将 decltype
生成出来的类型以字符形式打印出来, 但是标准库的type trait
模块提供了几个模板函数, 可以用来反向推导一个类型:
is_reference_v
是引用类型, 则可能是: T&
, T&&
; 不是引用类型, 则一定是: T
.
is_lvalue_reference_v
是左值引用类型, 则一定是: T&
; 不是左值引用类型, 则可能是: T
, T&&
is_rvalue_reference_v
是右值引用类型, 则一定是: T&&
; 不是右值引用类型, 则可能是: T
, T&
实体值(entity)
deceltype
不生产type
, 只是type
的搬运工.
#include <iostream>
using std::cout;
using std::endl;
using std::boolalpha;
using std::is_reference_v;
using std::is_lvalue_reference_v;
using std::is_rvalue_reference_v;
int main(void) {
// a 的类型是 int, 那么 decltype 生成的就是 int 类型.
int a = 10;
cout << "int a = 10;" << endl;
cout << "decltype(a);" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype(a)> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype(a)> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype(a)> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype(a)> << endl; // T&&
cout << endl;
cout << endl;
// a 的类型是 int &, 那么 decltype 生成的就是 int & 类型.
int & b = a;
cout << "int & b = a;" << endl;
cout << "decltype(b);" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype(b)> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype(b)> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype(b)> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype(b)> << endl; // T&&
cout << endl;
cout << endl;
// a 的类型是 int &&, 那么 decltype 生成的就是 int && 类型.
int && c = move(a);
cout << "int && c = move(a);" << endl;
cout << "decltype(c);" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype(c)> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype(c)> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype(c)> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype(c)> << endl; // T&&
cout << endl;
cout << endl;
// output
// int a = 10;
// decltype(a);
// T: true
// T& or T&&: false
// T&: false
// T&&: false
//
//
// int & b = a;
// decltype(b);
// T: false
// T& or T&&: true
// T&: true
// T&&: false
//
//
// int && c = move(a);
// decltype(c);
// T: false
// T& or T&&: true
// T&: false
// T&&: true
return 0;
}
表达式(expression)
If the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x) and decltype((x)) are often different types.
如果在decltype里面使用(T)
括号,那么decltype就会将这个(T)
当作一个表达式去推导. 请注意decltype在这里是根据value_category
去推导表达式的type
.
deceltype
不再是一个搬运工, 它会根据表达式返回的值的类别,来生成相应的type
.
#include <iostream>
using std::cout;
using std::endl;
using std::boolalpha;
using std::is_reference_v;
using std::is_lvalue_reference_v;
using std::is_rvalue_reference_v;
int main(void) {
// 加上(a)括号后, decltype将它视为一个表达式, a这个表达式,
// 可以使用 & 获取到地址, 因此它是一个 lvalue expression,
// lvalue expression 对应将生成 T&, 所以会命中:
// is_reference_v
// is_lvalue_reference_v
int a = 10;
cout << "int a = 10;" << endl;
cout << "decltype((a));" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype((a))> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype((a))> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype((a))> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype((a))> << endl; // T&&
cout << endl;
cout << endl;
// b 是 a 的别名, 因此它的结果跟 a 是一样的
int & b = a;
cout << "int & b = a;" << endl;
cout << "decltype((b));" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype((b))> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype((b))> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype((b))> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype((b))> << endl; // T&&
cout << endl;
cout << endl;
// rvalue reference, 也可以使用 & 获取地址, 因此它是一个 lvalue expression.
// 所以它的结果跟 a 和 b 都是一样的.
int && c = move(a);
cout << "int && c = move(a);" << endl;
cout << "decltype((c));" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype((c))> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype((c))> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype((c))> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype((c))> << endl; // T&&
cout << endl;
cout << endl;
// 10 这个表达式, 是一个 prvalue expression,
// 它不能使用 & 获取到地址, 因此 decltype 将会按照对应表给他生成 T, 所以会命中:
// !is_reference_v
cout << "decltype((10));" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype((10))> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype((10))> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype((10))> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype((10))> << endl; // T&&
cout << endl;
cout << endl;
// move(a) 这个表达式, 是一个 xvalue expression,
// 它不能使用 & 获取到地址, 因此 decltype 将会按照对应表给他生成 T&&, 所以会命中:
// is_reference_v
// is_rvalue_reference_v
cout << "decltype((move(a)));" << endl;
cout << "T: " << boolalpha << !is_reference_v<decltype((move(a)))> << endl; // T
cout << "T& or T&&: " << boolalpha << is_reference_v<decltype(((move(a))))> << endl; // T& or T&&
cout << "T&: " << boolalpha << is_lvalue_reference_v<decltype(((move(a))))> << endl; // T&
cout << "T&&: " << boolalpha << is_rvalue_reference_v<decltype(((move(a))))> << endl; // T&&
cout << endl;
cout << endl;
// output
// int a = 10;
// decltype((a));
// T: false
// T& or T&&: true
// T&: true
// T&&: false
//
//
// int & b = a;
// decltype((b));
// T: false
// T& or T&&: true
// T&: true
// T&&: false
//
//
// int && c = move(a);
// decltype((c));
// T: false
// T& or T&&: true
// T&: true
// T&&: false
//
//
// decltype((10));
// T: true
// T& or T&&: false
// T&: false
// T&&: false
//
//
// decltype((move(a)));
// T: false
// T& or T&&: true
// T&: false
// T&&: true
return 0;
}
使用场景
- 模板特化时检测参数类型使用.
- 返回值时根据某个变量的类型来生成相同类型.
参考
decltype
Is it possible to print a variable's type in standard C++?