C++ decltype类型说明符

一、decltype意义

有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了)。为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

二、作用

主要作用:返回操作的数据类型

三、特点

  1. decltype的自动类型推断会发生在编译期(和auto一样)
  2. 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;// 语法上没问题, 但是真这么做,会发生未预料行为。
}

参考博客:C++详解decltype含义,decltype主要用途

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值