decltype 使用

  1. 功能

    • decltype可以将给定的表达式或变量的类型推导出来,包含引用和指针。

    • 一般用于复杂表达式作为返回值的类型推导。

    • 可以用于补足c++11auto缺陷.

    • 编译阶段的事情,不会任何执行,表达式也不会执行。

  2. 类型规则

    • 规则一:声明类型,类型包含引用就有引用,没有引用也不会自行添加。

    • 规则二:返回值则根据返回值类型确定最终类型。

    • 规则三:表达式根据默认和重载得到的最终类型。不建议特别复杂的表达式。

  3. 声明类型分析

    • 案例一

      int main() {
         int a = 0;
         decltype(a) b;
         b.error();
      }
      
      • 最终bint类型.
    • 案例二

      #include <cassert>
      int main() {
         const int & a = 0;
         decltype(a) b = a;
         assert(&b == &a);
      }
      
      • 通过执行知道,ba是一个地址,是引用.
      • 而且类型基本类型也一致,所以类型是一致的.
    • 案例三

      #include<iostream>
      class T {
      public:
         T() { std::cout << "s"  << this << std::endl; }
         ~T() { std::cout << "e" << this << std::endl; }
      };
      int main() {
         const T && a = T();
         decltype(a) b = T();
         return 0;
      }
      
      • 只进行了两次的构造.
  4. 返回值推测

    • 案例一

      #include<vector>
      #include<iostream>
      template <typename T,typename I>
      auto show(T&& a, I i) -> decltype(a[i]) {
         std::cout << "cool" << std::endl;
         return std::forward<T>(a[i]);
      }
      int main() {
         std::vector<int> s = { 1,2,3,4 };
         decltype(show("123", 1)) a = 2;
         return 0;
      }
      
      • 这里就是,但是不会执行std::cout,因为并不会执行,在编译阶段确定了类型而已.
    • 案例二

      #include<vector>
      int main() {
         std::vector<int> s = { 1,2,3,4 };
         decltype(s[1]) a;
         return 0;
      }
      
      • vector进行索引返回的是引用,引用类型必须初始化,所以报错。
  5. 复杂表达式

    • 案例一

      int main() {
         decltype((1+2+3+4)) a = 1;
         return 0;
      }
      
      • 结果是int类型.
    • 案例二

      int main() {
         int a = 1;
         decltype((a)) b = 1;
         return 0;
      }
      
      • 对变量进行(var)操作得到的是对应的引用类型,C++11的新特性.
      • 所以这里编译报错.
  6. decltype的真正作用

    • 组合后的返回值,复杂表达式。

    • 说明

      • std::vector进行[],返回的一般都是&类型,但是bool则例外.
      • 那么对于下面的代码,则不严谨.
    • 简单代码

      template <typename T,typename I>
      auto show(T& a, I i) ->decltype(a[i]) {
         return a[i];
      }
      
      • 不好看.
    • 好看点

      template <typename T,typename I>
      auto show(T& a, I i) {
         return a[i];
      }
      
      • C++14才支持,而且有点小问题.
      • 提示,auto推导,C++11仅仅支持简单的单个表达式推导,不支持复杂的组合表达式.
      • 但是C++14支持,C++14这里正常编译.
      • 但是auto不支持引用类型推导.这里是基本类型,是个右值。
    • 支持引用

      template <typename T,typename I>
      decltype(auto) show(T& a, I i) {
         return a[i];
      }
      
      • auto表示类型推导,decltype表示按照decltype的规则进行,即何在一起就是支持引用类型推导。
      • 美中不足就是,这里仅仅支持了左值。虽然加一个const就可以支持右值,但是又不是这里讨论的手段,因为无法区分是操作的左值还是右值。
      • 操作左值和操作右值的意义是完全不一样的。
    • 支持右值引用

      template <typename T,typename I>
      decltype(auto) show(T&& a, I i) {
         return a[i];
      }
      
      • 支持右值,但是这里的a是左值,非匿名消亡值.
      • a[i]返回引用,show执行完就消亡,那么会导致引用悬空.
    • 完善最终版

      template <typename T,typename I>
      decltype(auto) show(T&& a, I i) {
         return std::forward<T>(a)[i];
      }
      
      • 转化为对应类型,调用对应类型的重载。然后左值返回引用,右值返回右值变量。
      void show() && {}
      void show() &{}
      
      
    • 不同修饰调用不同的函数

      • 函数名后面可以用修饰变量的修饰符修饰,&&,const,volatile,&,也可以任意组合.
      • 这些可以重载,调用会使用最匹配的版本.
      • 使用了修饰的就不能定义无修饰的版本. 即show()&就不能定义show()这种.
      • 不同修饰的可以根据语义返回不同的对象.这些函数的函数名也不一样.
  7. C++11

    • ()

      • 对一个变量加(),得到的是一个引用类型.
    • 注意

      • 返回值的时候用这种,可能会带来引用悬空的情况.
  8. 总结

    • decltype得到的是声明的类型.

    • 复杂表达式得到的是最终结果的类型,即运算后结果的声明类型.

    • C++14允许decltype(auto)组合完美的推测.C++11可以通过后置的方式达到同样的效果.C++14更加简洁.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值