实例代码
// 详解decltype含义,decltype主要用途
#include <iostream>
#include <functional>
#include <vector>
#include <map>
using namespace std;
class CT{
public:
int i;
int j;
};
int testf(){
return 10;
}
const int &&myfunctest(void) {
return 0;
}
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;
};
auto add(int a, int b)->decltype(a + b) {
return a + b;
};
int tf(int &i){
return i;
}
double tf(double &d){
return d;
}
template<typename T>
auto FuncTmp(T &tv)->decltype(tf(tv)){ // auto 在这里没有自动类型推断的含义,这里它只是返回类型后置语法的组成部分。
return tf(tv);
}
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;
}
decltype(auto) tf1(){
int i = 1;
return i;
}
decltype(auto) tf2(){
int i = 1;
return (i); // 加了括号导致返回 int& , 但是要用这个返回的东西,则就会导致不可预料的后果
}
int main(int argc, const char * argv[]) {
//一: decltype 含义和举例
// decltype:用于推导类型,对于一个给定的变量名或者表达式,decltype能够告诉你该名字或者表达式的类型。
// auto a = 10; //我们并不想用表达式的值初始化这个变量
// C++ 11, decltype(说明符) :主要作用:返回操作数的数据类型。
// decltype 特点:
//(a): decltype 的自动类型推断会发生在编译器(和auto一样)
//(b): decltype 不会真正计算表达式的值
//(1.1) decltype 后的圆括号中是个变量
const int i = 0;
const int &iy = i;
auto j1 = i; // j1 = int //传值方式推断:引用属性、const属性都会被抛弃的, j1 = int
decltype(i) j2 = 15; // j2 = const int。如果decltype中是个变量,则变量的const属性会返回。
decltype(iy) j3 = j2; // j3 = const int & 。如果decltype中是个变量,变量的const属性,以及引用属性&都会被返回。
// decltype 很循规蹈矩,有啥返回啥。
decltype(CT::i) a; // a = int; 类访问表达式
CT tmpct;
decltype(tmpct) tmpct2; // tmpct2 = CT
decltype(tmpct2.i) mv = 5;// int 类访问表达式
int x = 1, y = 2;
auto &&z = x; // x左值,auto = int& , z = int & 。万能引用
decltype(z) && h = y; // int &h = y; 这里用到了引用折叠规则(折叠成了左值)。
//(1.2) decltype 后的圆括号中非变量(是表达式)
// decltype 会返回表达式的结果对应的类型。
decltype(8) kkk = 5; // kkk int
int ii = 0;
int *pii = ⅈ
int &iiy = ii;
decltype(iiy + 1) jj; // j = int ,因为iiy + 1得到一个整形表达式
decltype(pii) k; // k = int* ; pii是个变量。
*pii = 4;
decltype(*pii) k2 = ii; // k2 = int&;
// *pii是指针pii所指向的对象,而且能够给这个对象赋值,所以*pii是个左值
// *pii是个表达式, 不是变量,因为它有*号
// 如果表达式结果能够作为赋值语句左边的值,那decltype 后返回的就是个引用。
// 所以这种情况要专门记:
// decltype 后边是个非变量的表达式,并且表示能够作为等号左边内容,返回的就是一个类似int &
decltype(ii) k3; // k3 = int ,ii 只是个变量
decltype((i)) iy3 = ii; // 如果在变量名外w额外增加了一层或者多层括号(),那么编译器就会把这个变量当成一个表达式
// 又因为变量可以作为等号左边的内容;最终iy3 = int &
(ii) = 6;
//结论 decltype((变量)) 的结果永远都是引用
//(1.3) decltype 后的圆括号中是函数
decltype(testf()) tmpv = 14; // tmpv的类型就是函数testf()的返回类型int。
// 这里编译器没有去调用过函数testf().只是使用函数testf()的返回值类型作为tmpv的类型
decltype(testf) tmpv2; // tmpv2 = int(void), 这个有返回类型,有参数类型,代表一种可调用对象。
// 标准库function用法,类模板:
function<decltype(testf)> ftmp = testf; //声明了一个function(函数)类型,用来代表一个可调用对象。
// 它所代表的可调用对象是一个int(void);
cout << ftmp() << endl; //10
decltype(myfunctest()) myy = 0; // myy = const int &&
//二: decltype 主要用途
//(2.1) 应付可变类型,一般decltype主要用途还是应用于模板编程中。
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.2) 通过变量表达式抽取变量类型
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;
//(2.3) auto 结合decltype构成返回类型后置语法
//如上面的 add 函数
int i11 = 19;
cout << FuncTmp(i11) << endl; // 19
double d = 28.1f;
cout << FuncTmp(d) << endl; // 28.1
//(2.4) decltype(auto) 用法 c++14才支持的语法
//a). 用于函数返回类型
int a11 = 100;
mydouble(a11) = 20; // int &
cout << a11 << endl; // a11 = 20;
decltype(mydouble1(a11)) b11 = a; // b = int&
//b). 用于变量声明中
int xx = 1;
const int &yy = 1;
auto zz = yy; // z = int , const 和引用 都没了
decltype(auto) zz2 = yy; // zz2 = const inyyt &;
// auto 丢掉的东西(const,引用),能够通过decltype(auto) 捡回来。
//c). 再说(x)
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;// 语法上没问题, 但是真这么做,会发生未预料行为。
//三:总结
system("pause");
return 0;
}