zoukankan      html  css  js  c++  java
  • c++11-17 模板核心知识(六)—— 理解auto推导规则

    上篇文章讲了模板参数的推导规则,其实auto的推导规则跟模板参数的推导基本上一样的,都是推导参数嘛。比如上篇文章的模板基本结构是:

    template<typename T>
    void f(ParamType param);
    
    ......
    f(expr);
    

    编译器使用expr来推断ParamTypeT

    那么对应在auto推导中,auto就对应了T,变量的type specifier就是ParamType

    auto x = 27;
    const auto cx = x;
    const auto& rx = x;     
    

    这里,cx的type specifier就是const auto,rx的type specifier就是const auto&.

    我们可以想象成在推导auto类型时,编译器就是在做一次模板参数类型推断:

    • 推断x :
    template<typename T>
    void func_for_x(T param);
    
    func_for_x(27);
    
    • 推断cx :
    template<typename T>
    void func_for_cx(const T param);
    
    func_for_cx(x);
    
    • 推断rx :
    template<typename T>
    void func_for_rx(const T& param);
    
    func_for_rx(x);
    

    在模板参数推导中,我们根据ParamType将情况分成了三类。在auto推导中,我们同样可以根据type specifier来分成三种情况:

    • type specifier是一个指针或者引用,但不是universal reference(或者叫forwarding references).
    • type specifier是一个universal reference。
    • type specifier既不是指针也不是引用。

    image

    Case 1 : type specifier是一个指针或者引用,但不是universal reference

    const auto& rx = x;     
    

    上面分析过,不再赘述。

    image

    Case 2 : type specifier是一个universal reference

    auto&& uref1 = x;         // x is int and lvalue, so uref1's type is int&
    auto&& uref2 = cx;      // cx is const int and lvalue, so uref2's type is const int&
    auto&& uref3 = 27;     // 27 is int and rvalue, so uref3's type is int&&
    

    image

    Case 3 : type specifier既不是指针也不是引用

    auto x = 27;
    const auto cx = x;
    

    image

    注意这个Case的情况,假如我们有个函数返回引用,我们使用auto接收返回值,如果我们想改变函数的返回值,那么必须用auto&,而不是auto,因为这里和函数模板参数推断规则一样,是pass-by-value,会忽略引用、const和volatile:

    int x = 50;
    
    int &f() { return x; }
    
    int main() {
    
      auto a1 = f();
      a1 = 10;        // x = 50
    
      auto &a2 = f();
      a2 = 20;      // x = 20
    
      return 0;
    }
    

    数组和函数类型推断

    在函数模板参数推断中讨论了数组和函数作为模板参数的推断情况,在auto类型推断中情况也是相同的:

    const char name[] = "R. N. Briggs";
    
    auto arr1 = name;            // arr1's type is const char*
    auto& arr2 = name;        // arr2's type is const char (&)[13]
    
    void someFunc(int, double);
    
    auto func1 = someFunc;              // func1's type is void (*)(int, double)
    auto& func2 = someFunc;           // func2's type is void (&)(int, double)
    

    auto与函数模板参数推断的区别

    从C++11起有4种选择可以定义一个整形变量:

    auto x1 = 27;
    auto x2(27);
    auto x3 = { 27 };
    auto x4{ 27 };
    

    最后两种是C++11的新特性:统一初始化(uniform initialization),就是这个造成了模板参数推导和auto类型推导的最大区别 :

    auto x1 = 27;                 // type is int, value is 27
    auto x2(27);                 // type is int, value is 27
    
    auto x3 = { 27 };           // type is std::initializer_list<int>, value is { 27 }
    auto x4{ 27 };               // type is std::initializer_list<int>, value is { 27 }
    

    特殊点在于:如果使用uniform initialization来进行auto类型推断,那么最终auto推断出的结果是std::initializer_list<int>

    所以下面的代码会编译报错:

    template <typename T> 
    void f(T param);
    
    f({11, 23, 9});
    

    但是如果指定ParamTypestd::initializer_list<T>,则可以正确的推断T的类型:

    template<typename T>
    void f(std::initializer_list<T> initList);
    
    f({ 11, 23, 9 });        // T deduced as int, and initList's type is std::initializer_list<int>
    

    C++14中更特殊的情况

    在C++14中,允许将函数返回值和lambda参数声明为auto,但是在这种情况下,auto的类型推断使用的是模板参数类型推断规则:

    auto createInitList() {
      return { 1, 2, 3 };             // error: can't deduce type for { 1, 2, 3 }
    }
    
    std::vector<int> v;
    
    …
    auto resetV = [&v](const auto& newValue) { v = newValue; };           // C++14
    
    …
    resetV({ 1, 2, 3 }); // error! can't deduce type  for { 1, 2, 3 }
    

    (完)

    朋友们可以关注下我的公众号,获得最及时的更新:

  • 相关阅读:
    css修炼宝典
    衡量优秀的卓越的前端工程师
    Bootstrap 快速人门案例——前端最火的插件
    前端开发小白必学技能—非关系数据库又像关系数据库的MongoDB快速入门命令(2)
    前端开发必学技能之一———非关系数据库又像关系数据库的MongoDB快速入门第一步下载与安装
    小米路由器未授权访问漏洞
    linux下更改ssh登录前的banner信息
    centos下编译安装Openssl
    S2-032代码执行
    SSRF漏洞学习
  • 原文地址:https://www.cnblogs.com/zhangyachen/p/14013607.html
Copyright © 2011-2022 走看看