一、decltype意义
有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了)。为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
二、作用
主要作用:返回操作的数据类型
三、特点
- decltype的自动类型推断会发生在编译期(和auto一样)
- decltype不会真正计算表达式的值。
四、用法
1. decltype后的圆括号中是个变量
class Test
{
public:
int m_i;
int m_j;
};
int main()
{
const int i = 0;
const int& j = i;
auto m = i; // m = int 传值方式推断:引用属性和const 属性都会被抛弃
decltype(j) k = 100; // k = const int 。如果decltype中是个变量,则变量的const属性和引用属性都会返回
decltype(Test::m_i) a; //a = int
Test test;
decltype(test) t; //t = Test
decltype(test.m_i) m = 5; //m = int
int x = 1, y = 2;
auto&& z = x; //万能引用
decltype(z) && h = y; //int &h = y; 引用折叠,折叠成了左值
using boost::typeindex::type_id_with_cvr;
cout << "a=" << type_id_with_cvr<decltype(k)>().pretty_name() << endl;
return 0;
}
注意:
1. auto 传值方式推断:引用属性和const 属性都会被抛弃
2. 如果decltype中是个变量,则变量的const属性和引用属性都会返回
2. decltype后的圆括号中非变量(是表达式)
decltype会返回表达式的结果对应的类型。
int main()
{
decltype(8) k = 5; //k = int
int i = 0;
int* p = &i;
int& q = i;
decltype(q + 1); //j = int,得到的是一个整型表达式
decltype(p) k = &i; //k = int *; k 是一个变量
decltype(*p) k1 = i; //
using boost::typeindex::type_id_with_cvr;
cout << "a=" << type_id_with_cvr<decltype(k1)>().pretty_name() << endl;
return 0;
}
3. decltype后的圆括号中是函数
int getSize();
int main(void)
{
int tempA = 2;
/*1.dclTempA为int*/
decltype(tempA) dclTempA;
/*2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize,*/
decltype(getSize()) dclTempB;
decltype(getSize) dclTempC; // dclTempC = int(void),这个有返回类型,有参数类型,代表一种可调用对象
return 0;
}
五、主要用途
1. 用于模板编程
template<typename T>
class CT1 {
public:
typename T::iterator iter; //迭代器类型
void getbegin(T& tmpc) {
// ...
iter = tmpc.begin();
}
};
template<typename T>
class CT2 {
public:
//typename T::iterator iter; //迭代器类型
decltype(T().begin) iter; // const std::vector<int>() 表示 生成该类型的临时对象。调用了这个临时对象的begin()
void getbegin(T& tmpc) {
// ...
iter = tmpc.begin();
}
};
class A {
public:
A() {
cout << "执行A构造函数" << endl;
}
~A() {
cout << "执行A析构函数" << endl;
}
int func() const {
cout << "执行A的func函数" << endl;
return 0;
}
int m_i;
};
int main(int argc, const char * argv[])
{
using conttype = std::vector<int>; //定义类型别名
conttype myarr = { 10, 30, 40 }; //定义该类型变量,现在myarr是个容器
CT1<conttype> ct1;
ct1.getbegin(myarr);
//如果对于const 常量容器,上面的处理就会报错,
//using conttype1 = const std::vector<int>; //定义类型别名
//conttype1 myarr = {10,30,40}; //定义该类型变量,现在myarr是个容器
//CT1<conttype1> ct1;
//ct1.getbegin(myarr);
//在C++98时代,这里要用模板偏特化来解决, 但c++ 11之后我们可以用 decltype 很容易解决这种问题
//如上:class CT2 模板类的编写
A().func(); // 生成了一个临时对象,调用临时对象的func()函数
// 执行了A构造,A的func() ,A的析构函数
//(const A()).func(); //本执行结果和上面一样
decltype(A().func()) aaa; // aaa = int ,根本没构造过A类对象; 也没有调用过func()
}
2. 通过变量表达式抽取变量类型
int main(int argc, const char * argv[])
{
vector<int> ac;
ac.push_back(1);
ac.push_back(2);
vector<int>::size_type mysize = ac.size();
cout << mysize << endl; // 2
decltype(ac)::size_type mysize2 = mysize; //抽取ac的类型 vector<int> ,所以这行相当于 vector<int>::size_type mysize2 = mysize;
cout << mysize2 << endl; // 2
typedef decltype(sizeof(0)) size_t; // sizeof(0) 等价于 sizeof(int)
size_t abc;
abc = 1;
}
3. auto 结合decltype构成返回类型后置语法
auto add(int a, int b)->decltype(a + b) {
return a + b;
};
int tf(int& i) {
return i;
}
double tf(double& d) {
return d;
}
auto add(int a, int b)->decltype(a + b) {
return a + b;
};
template<typename T>
auto FuncTmp(T& tv)->decltype(tf(tv)) { // auto 在这里没有自动类型推断的含义,这里它只是返回类型后置语法的组成部分。
return tf(tv);
}
int main(int argc, const char * argv[])
{
//如上面的 add 函数
int i11 = 19;
cout << FuncTmp(i11) << endl; // 19
double d = 28.1f;
cout << FuncTmp(d) << endl; // 28.1
}
4. decltype(auto) 用法 c++14才支持的语法
1. 用于函数返回类型
template<typename T>
T& mydouble(T& v1) {
v1 *= 2;
return v1;
}
template<typename T>
decltype(auto) mydouble1(T& v1) { // 把auto理解成要推导的类型。推导过程我们采用decltype
v1 *= 2;
return v1;
}
int main(int argc, const char * argv[])
{
int a11 = 100;
mydouble(a11) = 20; // int &
cout << a11 << endl; // a11 = 20;
decltype(mydouble1(a11)) b11 = a11; // b = int&
}
2. 用于变量声明中
int main(int argc, const char * argv[])
{
int xx = 1;
const int& yy = 1;
auto zz = yy; // z = int , const 和引用 都没了
decltype(auto) zz2 = yy; // zz2 = const inyyt &;
// auto 丢掉的东西(const,引用),能够通过decltype(auto) 捡回来。
}
3. 再说(x)
int main(int argc, const char * argv[])
int iii = 10;
decltype((iii)) iiiy3 = iii; // iiiy = int &;
decltype(tf1()) testa = 4; // int
int aaaa = 1;
decltype(tf2()) testb = aaaa; // testb = int &
tf2() = 12;// 语法上没问题, 但是真这么做,会发生未预料行为。
}