zoukankan      html  css  js  c++  java
  • 模板类型推导、auto推导

           effective modern c++ 果然是神书,干货满满,简单记录下。

           item1 模板推倒

          

           典型的模板函数

            temlate<class T>

           void fn(ParamType param)   

    要记住的东西
    在模板类型推导的时候,有引用特性的参数的引用特性会被忽略
    在推导通用引用参数的时候,左值会被特殊处理
    在推导按值传递的参数时候,const和/或volatile参数会被视为非const和非volatile
    在模板类型推导的时候,参数如果是数组或者函数名称,他们会被退化成指针,除非是用在初始化引用类型

         

           当ParamType 是指针或者引用时,  

    1. 如果expr的类型是个引用,忽略引用的部分。

    2. 然后利用expr的类型和ParamType对比去判断T的类型。

         

    template<typename T>
    void f(T& param);           // param是一个引用类型
    
    int x = 27;                 // x是一个int
    const int cx = x;           // cx是一个const int
    const int& rx = x;          // rx是const int的引用
    
    f(x);                       // T是int,param的类型时int&
    
    f(cx);                      // T是const int,
                                // param的类型是const int&
    f(rx);                      // T是const int
                                // param的类型时const int&

         当ParamType  是右值引用时,(注意到param是左值时的特殊性)

       

    • 如果expr是一个左值,TParamType都会被推导成左值引用。这有些不同寻常。第一,这是模板类型T被推导成一个引用的唯一情况。第二,尽管ParamType利用右值引用的语法来进行推导,但是他最终推导出来的类型是左值引用。

    • 如果expr是一个右值,那么就执行“普通”的法则(第一种情况)

    template<typename T>
    void f(T&& param);            // param现在是一个通用的引用
    
    int x = 27;                 // 和之前一样
    const int cx = x;           // 和之前一样
    const int& rx = x;          // 和之前一样
    
    f(x);                        // x是左值,所以T是int&
                                // param的类型也是int&
    
    f(cx);                        // cx是左值,所以T是const int&
                                // param的类型也是const int&
    
    f(rx);                        // rx是左值,所以T是const int&
                                // param的类型也是const int&
    
    f(27);                        // 27是右值,所以T是int
                                // 所以param的类型是int&&

        当ParamType 既不是指针也不是引用时,按照pass by value 来

    1. 和之前一样,如果expr的类型是个引用,将会忽略引用的部分。

    2. 如果在忽略expr的引用特性,expr是个const的,也要忽略掉const。如果是volatile,照样也要忽略掉(volatile对象并不常见。它们常常被用在实现设备驱动上面。查看更多的细节,请参考条款40。)

    int x = 27;                 // 和之前一样
    const int cx = x;           // 和之前一样
    const int& rx = x;          // 和之前一样
    
    f(x);                       // T和param的类型都是int
    
    f(cx);                      // T和param的类型也都是int
    
    f(rx);                      // T和param的类型还都是int

        最后再来个大杀器

       

    //数组的引用再理解下
    //int a[]={1,2,3}   --> a的类型是啥?  int [3]
    //int & rb   --->rb的类型是啥? rb先与&结合,表明是个引用,然后接触int 表明是个int型的引用
    //int (&ra)[]={1,2,3} -->ra的类型是啥? ra先与&结合,表明是个引用,然后接触 int [3] 是个int [3] 的引用
    //那如果去掉ra的形参,如何写呢  int (&) [3]  ,这是个类型,并且是int [3] 的引用
    
    //计算数组长度 constexpr需要vs2015以上
    template<class T, std::size_t SIZE>
    constexpr std::size_t ConstArraySize(T(&)[SIZE])
    {
        return SIZE;
    }
    
    template<class T, std::size_t SIZE>
    std::size_t ArraySize(T(&)[SIZE])
    {
        return SIZE;
    }

    item2 auto 推导

         能够理解item1的话,这个就好办了,这个和item1的推导几乎一模一样。

         item1的关键有个T 和ParamType 需要推导,对于auto来说,T就是auto!这么说有点困难,我们例子来说明

         auto x = 27;                           //T 是auto  ParamType也是auto  即item1上的规则3,pass by value

         const auto cx = x;                 //T 是auto   ParamType是 const auto ,按照规则3 

         auto& rx = x;                        //T 是auto    ParamType是 auto &          按照规则1

          

    auto&& uref1 = x;                   // x是int并且是左值
                                        // 所以uref1的类型是int&
    
    auto&& uref2 = cx;                  // cx是int并且是左值
                                        // 所以uref2的类型是const int&
    
    auto&& uref3 = 27;                  // 27是int并且是右值
                                        // 所以uref3的类型是int&&
    
    const char name[] =                 // name的类型是const char[13] 
        "R. N. Briggs";
    
    auto arr1 = name;                   // arr1的类型是const char*
    
    auto& arr2 = name;                  // arr2的类型是const char (&)[13]
    
    void someFunc(int, double);         // someFunc是一个函数,类型是
                                        // void (*)(int, double)
    
    auto& func2 = someFunc;             // func1的类型是
                                        // void (&)(int, double)

    到此为止,我们都非常成功,接下来是auto 与模板推导不同的地方

    auto x1 = 27;                       // 类型时int,值是27
    
    auto x2(27);                        // 同上
    
    auto x3 = { 27 };                   // 类型是std::intializer_list<int>
                                        // 值是{ 27 }
    
    auto x4{ 27 };                      // 同上
    
    auto x5 = { 1, 2, 3.0 };            // 错误! 不能讲T推导成
                                        // std::intializer_list<T>
    
    auto x = { 11, 23, 9 };             // x的类型是
                                        // std::initializer_list<int>
    
    template<typename T>                // 和x的声明等价的
    void f(T param);                    // 模板
    
    f({ 11, 23, 9 });                   // 错误的!没办法推导T的类型
    
    template<typename T>
    void f(std::initializer_list<T> initList);
    
    f({ 11, 23, 9 });                   // T被推导成int,initList的
                                        // 类型是std::initializer_list<int>
    要记住的东西
    auto类型推导通常和模板类型推导类似,但是auto类型推导假定花括号初始化代表的类型是std::initializer_list,但是模板类型推导却不是这样
    auto在函数返回值或者lambda参数里面执行模板的类型推导,而不是通常意义的auto类型推导

     

     

          

     

               

     

     

     

     

     

     

     

  • 相关阅读:
    支持国产共享软件
    Win CE 5.0 增加电池电量显示
    [转]C# 系统应用之鼠标模拟技术及自动操作鼠标
    自己写的 读写 ini 配置文件类
    自己写的 Readini 类
    sizeof与strlen()、递归优化题解
    Git学习资源收集汇总
    好用的Google Chrome插件
    【转】C# Socket编程(5)使用TCP Socket
    【转】C# Socket编程(4)初识Socket和数据流
  • 原文地址:https://www.cnblogs.com/xuhuajie/p/11472641.html
Copyright © 2011-2022 走看看