模板推导

PT         expr         PT结果        T 

T&         int          int&         int

T&         int&         int&         int
T&         const int    const int&   const int
T&         const int&   const int&   const int
T&         int*         int *&      int*

T&         const int*   int const*&  int const*

const T&   const int    const int&   int

const T&   const int&   const int&   int
const T&   int          const int&   int
const T&   int&         const int&   int
T*         int*         int*         int
T*         const int*   const int*   const int
const T*   int*         const int*   int
const T*   const int*   const int*   int
T          int          int          int
T          int&         int          int
T          const int    int          int
T          const int&   int          int
T          int*         int*         int*
T          const int*   const int*   const int* 

上面蓝色处是因为模板推导为值传递时,expr为const int,const int&时根本无意义,值传递是直接复制的,无法保证其const 属性。

template<typename T>

void f(ParamType param);
在整个编译期间,编译器用expr来推导两个类型:一个是T ,另一个是ParamType 。这两个类型常常是不一样的,
因为ParamType常常包含一些修饰符。(比如const或引用的限定) 对T类型的推导,不仅仅取决于expr ,同时也取决于ParamType
这里有三种情况
1.ParamType是指针或引用,但不是一个universal引用
2.ParamType是universal引用
3.ParamType不是指针也不是引用
1.ParamType是指针或引用,但不是一个universal引用.(即ParamType是T&,const T&,T*,const T*)
  替换流程是1.(expr是引用,去除引用,剩下的类型匹配ParamType决定T)

                 

  
2.待续
 
3.ParamType不是指针也不是引用.(即ParamType是T) 这意味着,param将成为传入参数的一份拷贝,一个全新的对象,可以被修改的对象.
  替换流程是1.expr先去除引用,再去除用const和volatile(如果包含),剩下的类型匹配ParamType决定T)
  
  字符串参数:
  template<typename T>
  void f(T param);
  cosnt char* cosnt ptr = "Fun with pointers";
  f(ptr); //T是const char*,param的类型是const char*
  
  数组参数:
  template<typename T>
   void f(T param);
   const char name[] = "J.P.Briggs";
   f(name); //name是数组,但是T被推导成cosnt char*
   
   
  特殊:
   template<typename T>
   void f(T& param); //T被推导成cosnt char[13],param -> cosnt char(&)[13]或者
   
  函数参数:
  void someFunc(int, double);
  template<typename T>
  void f1(T param);
  template<typename T>
  void f2(T& param);
  f1(someFunc);   //T是void (*)(int, double)
  f2(someFunc);   //T是 void (&)(int, double)
  
            你要记住的事
在template类型推导的时候,references类型的参数被当成non-references。也就是说引用属性会被忽略。
当推导universal类型的引用参数时,左值参数被特殊对待。
当推导传值(by-value)类型参数时,cosnt 和/或 volatile 参数被当成 non-const 和 non-volatile。
当推导类型是数组或函数时会退化成指针,除非形参是引用.
右值一般情况:
函数返回值就是右值.

 

auto * a = &x;//a -> int*,auto被推导为int  
auto   b = &x;//b -> int*,auto被推导为int*  
auto & c = x;//c -> int&,auto被推导为int  
auto   d = c;//d -> int,auto被推导为int  
 
const auto e = x;//e -> const int  
auto f = e;//f -> int  
const auto& g = x;//g -> const int&  
auto& h = g;//h -> const int& 
a和c的推导结果是很显然的,auto在编译时被替换为int,因此a和c分别被推导为int*和int&。
b的推导结果说明,其实auto不声明为指针,也可以推导出指针类型。
d的推导结果说明当表达式是一个引用类型时,auto会把引用类型抛弃,直接推导成原始类型int。
e的推导结果说明,const auto会在编译时被替换为const int。
f的推导结果说明,当表达式带有const(实际上volatile也会得到同样的结果)属性时,auto会把const属性抛弃掉,推导成non-const类型int。
g、h的推导说明,当auto和引用(换成指针在这里也将得到同样的结果)结合时,auto的推导将保留表达式的const属性。
通过上面的一系列示例,可以得到下面这两条规则:
1)当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符后类型一致。
2)当声明为指针或引用时,auto的推导结果将保持初始化表达式的cv属性。
比如上面例子中的auto,和下面的模板参数自动推导出来的类型是一致的:
template <typename T> void func(T   x) {}   // T   -> auto  
template <typename T> void func(T * x) {}   // T * -> auto *  
template <typename T> void func(T & x) {}   // T & -> auto &  
 
template <typename T> void func(const T   x) {} // const T   -> 
const auto  
template <typename T> void func(const T * x) {} // const T * -> 
const auto *  
template <typename T> void func(const T & x) {} // const T & -> 
const auto & 
因此,在熟悉auto推导规则时,可以借助函数模板的参数自动推导规则来帮助和加强理解。

 

 #include <iostream>
#include <type_traits>
#include <string>
using namespace std;
template<typename T>
void fun(T p)
{
    std::cout<<std::is_same<T,  const  int*>::value<<endl;
}
int main()
{
    int j = 0;
    const int i = 0;
    const int ci=i,&cr=i;
    auto a=ci;      //a为int(忽略顶层const)
    auto b=cr;      //b为int(忽略顶层const,cr是引用)
    auto c=&i;      //c为const int *
    auto d=&ci;     //d是const int *(&ci为底层const)
    std::cout<<std::is_same<decltype(cr),  const int &>::value<<endl;
    std::cout<<std::is_same<decltype(a),   int>::value<<endl;
    std::cout<<std::is_same<decltype(b),   int>::value<<endl;
    std::cout<<std::is_same<decltype(c),   const int*>::value<<endl;
    std::cout<<std::is_same<decltype(d),   const int*>::value<<endl;
    std::cout<<std::is_same<decltype(&i),   const int*>::value<<endl;
    const int *pp = &i;
    fun(pp);
} 

 

全为1 

auto x = 11; //类型3, auto推导为int
const auto cx = x; // 类型3, auto推导为int, cx类型为int const
auto& rx = x; //类型1, auto推导为int, rx类型为int& 
auto&& uref1 = x; //左值,auto推导为int&, uref1类型为int& 
auto&& uref2 = cx; //左值,auto推导为const int&, uref2类型为const int& 
auto&& uref3 = 11; //右值,auto推导为int, uref3类型 int&& 
const char name[] = "C++11" ;
auto arr1 = name; // auto推导为const char*, arr1类型const char* 
auto& arr2 = name; //auto推导为const char[6], arr2类型为const char(&)[6] void someFunc(int, double);
auto func1 = someFunc(); //auto推导为void(*)(int, double), func1类型为void(*)(int, double)
auto& func2 = someFunc();//auto推导为void(int, double),func2类型为void(&)(int, double) 
  
posted on 2016-11-02 15:39  abelian  阅读(175)  评论(0)    收藏  举报