c++11decltype关键字详解

decltype关键字总结

decltype概述

decltype也是用来进行类型推导的,这一点与auto比较类似。假如有这样一种场景,希望从表达式的类型推断出要定义的变量的类型,但是又不希望用表达式的值去初始化该变量(auto必须要初始化),那要怎么做?所以c++11新标准引入了decltype关键字,也叫说明符,它的作用主要就是用来返回操作数的数据类型的。

decltype推导分类

变量

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int main()
{
  const int i = 0;
  const int& j = i;
  //会保留const属性
  decltype(i) i2 = 10;
  cout << "i = " << type_id_with_cvr<decltype(i)>().pretty_name() << endl;
  //会保留const,以及引用属性
  decltype(j) j2 = i;
  cout << "j = " << type_id_with_cvr<decltype(j)>().pretty_name() << endl;
  //decltype也是可以用在类或者结构体当中的
  decltype(A::a) p;
  cout << "A::a = " << type_id_with_cvr<decltype(A::a)>().pretty_name() << endl;
  cout << "p = " << type_id_with_cvr<decltype(p)>().pretty_name() << endl;
  return 0;
}

在这里插入图片描述

表达式

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int main()
{
    /*来分析decltype后面的()圆括号当中是表达式的类型。
    */
    int i = 10;
    decltype(i + 10) j = 20;
    cout << "i+10 = " << type_id_with_cvr<decltype(i+10)>().pretty_name() << endl;
    int* p = &i;
    cout << "*p = " << type_id_with_cvr<decltype(*p)>().pretty_name() << endl;
    cout << "p = " << type_id_with_cvr<decltype(p)>().pretty_name() << endl;
    return 0;
}

在这里插入图片描述
分析上面的结果,比较纳闷的是星号p为什么会是一个引用呢?按照正常理解应该是一个int啊,因为星号p在这里是一个表达式,而不会是一个变量,因为带有星号,在这里要专门的记一下,如果表达式的结果能够作为赋值语句等号左侧的值,比如*p = 10;那么decltype推导出来的就是一个引用。

这里还有一种情况要说明一下,如果()里面是一个变量,那么如果再加一个括号,比如decltype((变量)),,那么编译器就会把这个变量当中一个表达式去推导,而且因为变量是可以放在等号左侧的,所以返回的依旧是一个引用。

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int main()
{
    int i = 10;
    cout << "(i) = " << type_id_with_cvr<decltype((i))>().pretty_name() << endl;
    return 0;
}

在这里插入图片描述

函数

#include <iostream>
#include <boost/type_index.hpp>
#include <functional>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int func()
{
    std::cout << "func" << std::endl;
    return 10;
}
int main()
{
    /*从运行结果可以看到,实际上,func函数是没有被调用的*/
    decltype(func()) i = 1;
    cout << "func() = " << type_id_with_cvr<decltype(func())>().pretty_name() << endl;
    cout << "i = " << type_id_with_cvr<decltype(i)>().pretty_name() << endl;

    /*function是一个类模板*/
    function<decltype(func)> p = func;
    cout << "func = " << type_id_with_cvr<decltype(func)>().pretty_name() << endl;
    p();//调用func()函数
    return 0;
}

在这里插入图片描述

decltype的应用

decltype用在模板编程当中比较多,下面将decltype的应用分成了以下的几大类。

应付可变类型

在这里插入代码片

通过变量表达式抽取变量类型

#include <iostream>
#include <boost/type_index.hpp>
#include <vector>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int main()
{
    vector<int> vec;
    vec.push_back(1);
    vector<int>::size_type size = vec.size();
    cout << size << endl;
    //等价于vector<int>::size_type i
    decltype(vec)::size_type i = vec.size();

    cout << "vec= " << type_id_with_cvr<decltype(vec)>().pretty_name() << endl;
    return 0;
}

结合auto构成返回类型后置语法

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int tf(int i)
{
    return i;
}
/*后置返回类型,利用tf函数的返回结果推导出tmp函数的返回类型*/
template<typename T>
auto tmp(T v) -> decltype(tf(v))
{
    return tf(v);
}
int main()
{
    tmp(10);
    return 0;
}

如下的写法如果用decltype就不对了。

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int tf(int i)
{
    return i;
}
//错误,v是未定义的标识符,因为v出现在在tmp函数的形参里,比decltype出现的时机晚。
template <typename T>
decltype(tf(v)) tmp(T v)
{
    return tf(v);
}
int main()
{
    return 0;
}

总结:如果在现在的这种语义下,返回值后置的语法还是很必要的,当然,你用auto也行,这里只是演示以下错误的情形。

decltype(auto)用法

decltype(auto)的用法出现在c++14当中,建议将编译器的版本升级到c++14以上中,避免编译不通过的情况。
用于函数返回类型:

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
template<typename T>
T& fun(T& v)
{
    return v;
}
int main()
{
    int i = 10;
    std::cout << fun(i) << std::endl;
    fun(i) = 100;
    std::cout << i << std::endl;
    return 0;
}

现在一切正常,修改一下代码,

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
template<typename T>
auto fun(T& v)
{
    return v;
}
int main()
{
    int i = 10;
    //fun(i) = 100; //错误,因为auto在这里会抛弃引用属性,所以fun(i)是一个右值,在这里赋值显然是不行的
   cout << "func = " << type_id_with_cvr<decltype(fun(i))>().pretty_name() << endl;
    return 0;
}
template<typename T>
decltype(auto) fun(T& v)
{
    return v;
}
//当然用auto也可以解决这个问题
template <typename T>
auto& fun(T& v)
{
    return v;
}

用在变量当中:

#include "ModbusTcpMaster.h"
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;
int main(int argc, char** argv)
{
    const int& x = 1;
    auto y = x;
    //如果用auto的话,const和&的属性都会丢弃
    cout << "y = " << type_id_with_cvr<decltype(y)>().pretty_name() << endl;
    //如果用decltype的话,const和&的属性都会保留
    decltype(auto) z = x;
    cout << "z = " << type_id_with_cvr<decltype(z)>().pretty_name() << endl;
    return 0;
}

在这里插入图片描述
用在(),表达式当中:

#include "ModbusTcpMaster.h"
#include <boost/type_index.hpp>
using namespace std;
using boost::typeindex::type_id_with_cvr;

decltype(auto) fun()
{
    int i;
    return (i);
}
int main(int argc, char** argv)
{
    fun() = 10; //int &,,相当于绑定了i,,,但是要注意虽然返回的是引用,但是要注意,i的作用域。
    cout << "fun() = " << type_id_with_cvr<decltype(fun())>().pretty_name() << endl;
    return 0;
}

decltype特点总结以及与auto对比

特点:
(1)decltype的自动类型推断也发生在编译期间,这点和auto一样
(2) decltype不会真正计算表达式的值
(3) const限定符,引用属性有可能会被auto抛弃,但是,decltype一般不会抛弃任何东西。
总结:decltype的用法很多,随着我们以后会阅读越来越多的代码,相信我们也会对它理解的更加的深刻。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值