decltype 是“declare type”的缩写,译为“声明类型”。 C++11 新增的一个关键字,和 auto 的功能一样,都用来在编译时期进行自动类型推导。
decltype 能够根据变量、字面量、带有运算符的表达式推导出变量的类型
decltype(exp) varname;
exp 就是一个普通的表达式,它可以是任意复杂的形式,但是必须要保证 exp 的结果是有类型的,不能是 void;例如,当 exp 调用一个返回值类型为 void 的函数时,exp 的结果也是 void 类型,此时就会导致编译错误。
int a = 0;
decltype(a) b = 1; //b 被推导成了 int
decltype(10.8) x = 5.5; //x 被推导成了 double
decltype(x + 100) y; //y 被推导成了 double
auto 和 decltype 关键字都可以自动推导出变量的类型,但用法是有区别的:
auto varname = value;
decltype(exp) varname = value;
varname 表示变量名,value 表示赋给变量的值,exp 表示一个表达式。
#include
using namespace std;
class Student{
public:
static int total;
string name;
int age;
float scores;
};
int Student::total = 0;
int main(){
int n = 0;
const int &r = n;
Student stu;
decltype(n) a = n; //n 为 int 类型,a 被推导为 int 类型
decltype(r) b = n; //r 为 const int& 类型, b 被推导为 const int& 类型
decltype(Student::total) c = 0; //total 为类 Student 的一个 int 类型的成员变量,c 被推导为 int 类型
decltype(stu.name) url = "http://c.biancheng.net/cplus/"; //total 为类 Student 的一个 string 类型的成员变量, url 被推导为 string 类型
return 0;
}
//函数声明
int& func_int_r(int, char); //返回值为 int&
int&& func_int_rr(void); //返回值为 int&&
int func_int(double); //返回值为 int
const int& fun_cint_r(int, int, int); //返回值为 const int&
const int&& func_cint_rr(void); //返回值为 const int&&
//decltype类型推导
int n = 100;
decltype(func_int_r(100, 'A')) a = n; //a 的类型为 int&
decltype(func_int_rr()) b = 0; //b 的类型为 int&&
decltype(func_int(10.5)) c = 0; //c 的类型为 int
decltype(fun_cint_r(1,2,3)) x = n; //x 的类型为 const int &
decltype(func_cint_rr()) y = 0; // y 的类型为 const int&&
using namespace std;
class Base{
public:
int x;
};
int main(){
const Base obj;
//带有括号的表达式
decltype(obj.x) a = 0; //obj.x 为类的成员访问表达式,符合推导规则一,a 的类型为 int
decltype((obj.x)) b = a; //obj.x 带有括号,符合推导规则三,b 的类型为 int&。
//加法表达式
int n = 0, m = 0;
decltype(n + m) c = 0; //n+m 得到一个右值,符合推导规则一,所以推导结果为 int
decltype(n = n + m) d = c; //n=n+m 得到一个左值,符号推导规则三,所以推导结果为 int&
return 0;
}
auto 只能用于类的静态成员,不能用于类的非静态成员(普通成员),如果推导非静态成员的类型,这个时候就必须使用 decltype 了
#include
using namespace std;
template <typename T>
class Base {
public:
void func(T& container) {
m_it = container.begin();
}
private:
typename T::iterator m_it; //注意这里
};
int main()
{
const vector<int> v;
Base<const vector<int>> obj;
obj.func(v);
return 0;
}
单独看 Base 类中 m_it 成员的定义,很难看出会有什么错误,但在使用 Base 类的时候,如果传入一个 const 类型的容器,编译器马上就会弹出一大堆错误信息。原因就在于,T::iterator并不能包括所有的迭代器类型,当 T 是一个 const 容器时,应当使用 const_iterator。
有了 C++11 的 decltype 关键字,就可以直接这样写:
template <typename T>
class Base {
public:
void func(T& container) {
m_it = container.begin();
}
private:
decltype(T().begin()) m_it; //注意这里
};