一、类型转换与模板类型参数
1、如果一个函数形参的类型使用了模板类型参数,那么它采用特殊的初始化规则。只有很有限的几种类型转换会自动地应用于这些实参。
①、顶层const无论是在形参中还是在实参中,都会被忽略。
②、const转换:可以将一个非const对象的引用(或指针)传递给一个const的引用(或指针)形参。
③、数组或函数指针转换:如果函数形参不是引用类型,则可以将对数组或函数类型的实参应用于正常的指针转换。
如下程序所示:
1 template<typename T> T fobj(T,T);//实参被拷贝 2 template<typaname T> T freb(const T&, const T&);//const引用 3 4 std::string s1("a value"); 5 const string s2("another value"); 6 fobj(s1,s2);//fobj(string,string);顶层const被忽略 7 freb(s1,s2);//fobj(const string&, const string&) 非const转换为const 8 9 int a[10],b[42]; 10 fobj(a,b);//将调用fobj(int*, int*); 11 fref(a,b);//错误 数组类型不匹配
二、函数模板显示实参
1、在某些情况下,编译器无法推断出模板实参的类型。返回类型就是典型例子,当返回类型与参数列表中任何类型都不相同时,这种情况最常见。在这种情况下,我们显示指定模板实参。
我们可以定义表示返回类型的第三个模板实参,从而允许用户控制返回类型:
1 template <typename T1, typename T2, typename T3> 2 T1 sum(T2,T3);
调用时显示指定返回类型:auto val3 = sum<long long>(i,lng);
三、我们可以通过第二种方式来设置返回类型-尾置返回类型,这样就可以减少用户额外负担。
template <typename It> auto fcn(It beg, It end) -> decltype(*beg) { return *beg; }
此例中,解引用运算符返回一个左值,因此通过decltype推断的类型为beg表示元素类型的引用。因此如果对一个string序列调用fcn,返回类型将是string&;
3、可以对类型转换的标准库模板。这里我们简单介绍。一个是remove_reference来获得元素的类型。remove_reference<string &>::type将得到string。
四、函数指针和实参推断。。。
五、模板实参推断和引用
1、如果一个函数模板类型参数的类型是T&,绑定规则告诉我们,只能传递给它一个左值。
2、如果一个函数模板类型参数的类型是const T&,正常的绑定规则告诉我们可以传递给它任何类型的实参。注:const已经是函数参数类型一个部分。
3、如果一个函数模板类型参数的类型是T&&,正常绑定规则告诉我们应该传递给它一个右值,其实不尽然,这里存在这两个例外。
①:当我们将一个左值传递给函数的右值引用参数,编译器推断出类型参数为实参的左值的引用类型。通常,我们不能定义一个引用的引用。但是,通过类型别名或通过模板类型参数间接定义是可以的。
②:如果我们间接创建一个引用的引用,,则这些引用形成了“折叠”。除了右值引用的右值引用会折叠成右值引用,其它都会折叠成左值引用。
4、通常使用右值引用的函数模板,我们都会进行函数重载。如下
1 template<typename T> void f(T&&);//绑定到非const右值 2 template<typename T> void f(const T&);//左值和const右值
六、std::move
template <typename T> typename remove_reference<T>::type&& move(T&& t) { return static_cast< typename remove_reference<T>::type&&>(t); }
T = string,则会被实例化为string&& move(string&& t);
T = string&,则会被实例化为string&& move(string& t);
七、转发