第4课 模板的细节改进
Posted 浅墨浓香
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第4课 模板的细节改进相关的知识,希望对你有一定的参考价值。
1. 右尖括号的问题
(1)在实例化模板时,会出现两个连续右尖括号(>>),如:
①vector<list<int> >; //注意,两个右尖括号之间有空格。C++98/03/11均支持
②vector<list<int>>; //c++11开始支持这种写法!在C++98/03将连写的>>当成右移操作符,该行会编译出错!
(2)强制类型转换出现的两个连续右尖括号
const vector<int> v = static_cast<vector<int>>(v); //C++98/03不支持,C++11支持。
(3)特殊应用出现的连续右尖括号,如
Template<int i> class Test{};
Test<100 >> 2> t; //C++98/03“>>”被看作是右移操作符。C++11不这样认为,应改为Test<(100 >> 2)> t;即加个括号。
【编程实验】右尖括号
//main.cpp
#include <iostream> #include <vector> using namespace std; //编译选项:g++ test.cpp // g++ -std=c++11 test.cpp //关于Foo和Bar词源的一类说法: //1.foobar又为foo-bar,其中的bar是beyond all recognition的缩写, // 意为无法识别,一塌糊涂的意思。 //2. foo是fu的变体,是fuck-up的缩写,同样是一团糟的意思。 template <typename T> struct Foo { typedef T type; }; template <int N> struct Bar { }; int main() { Foo<vector<int>>::type f1; //C++98/03中">>"被看作右移操作符!编译出错 //C++11中是合法的! Foo<decltype(100 >> 2)> f2; //相当于:Foo<int> f2; //Bar<100 >> 2> b1; //100/4=25,C++98/03会将>>看作右移操符符,合法! //C++11不认为>>是右移操作符,编译错误!改进如下: Bar<(100 >> 2)> b2; //加一个小括号,改变优先级 return 0; }
2. 模板的别名
(1)typedef和using关键字
①类模板(class template)和模板类(template class)的不同:类模板是用来产生类的模板,是一种模板。而“模板类”是用该模板产生出来的类,是一种类型。
②typedef可以定义类型的别名,但不能用来重定义模板的别名。
③C++11引入using关键字,它覆盖了typedef的全部功能。既可以用来定义类型的别名,也可以定义模板的别名。而且采用类似于赋值的方式,从语法比typedef更加清晰。
//****************using覆盖了typedef的全部功能******************* //重定义unsigned int,两者等价 typedef unsigned int uint_t; using uint_t = unsigned int; //重定义std::map,两者等价 typedef std::map<std::string, int> map_int_t; //OK,为模板类重定义别名。注意,这里是模板类 //而不是类模板。模板类本质是一种类型,而不是模板! using map_int_t = std::map<std::string, int>; //使用using关键字 //重定义函数指针,两者等价 typedef void(*func_t)(int, int); using func_t = void(*)(int, int);
(2)两种定义模板别名的方式比较
①C++98/03中为模板重定义别名时,需要外加一个包装类才能为模板定义别名,使用烦琐。
②using可以轻松地为模板重定义别名。只需要在普通类型别名的语法基础前加上template的参数列表,如template<typename T1, int N>。
【编程实验】using关键字及模板的别名
//*********两种为模板定义别名的比较(以重定义函数模板为例)******* //1. 使用包装类+typedef(C++98/03) template <typename T> struct func_t { typedef void(*type)(T, T); }; func_t<int>::type func1;//使用时 //2. 使用using关键字(C++11) template <typename T> using func_t = void(*) (T, T); func_t<int> func2;
3. 函数模板的默认模板参数
(1)类模板和函数模板的默认模板参数
①在C++98/03中,类模板可以有默认参数,但不支持函数模板的默认参数。而C++11中同时支持类和函数模板的默认模板参数。
②当所有模板参数都有默认参数时,函数模板的调用与普通函数一致。但对于类模板,在使用时也须在模板名称后跟“<>”来实例化。
③在为多默认模板参数的类模板指定默认值时(声明时),必须遵照“从右往左”的规则进行指定。而函数模板没有这个限制,同时当调用多默认模板参数的函数模板时如果显式指定模板的参数,则参数填充的顺序是从左往右的。
(2)函数模板的参数推导规则(按优先级从高到低):template<typename T = int> void func(T val = 0){};
①显式指定类型。如func<float>(0);
②自动推导类型:如func<3.14>,编译器将推导出T为double。
③模板参数的默认值,如func(),默认T为int。
【编程实验】函数模板的默认模板参数
#include <iostream> #include <typeinfo> using namespace std; //编译选项:g++ test.cpp // g++ -std=c++11 test.cpp //********测试不同版本C++对类模板和函数模板默认模板参数的支持************* template<typename T = int> class A{}; //C++98/03编译通过,C++11编译通过 template<typename T = int> void func1() {}; //C++98/03编译失败,C++11编译通过 //**************在声明时为多个默认模板参数指定默认值********************** //为类模板指定默认模板参数 template<typename T1, typename T2 = int> class C1; //从右往左指定,OK //template<typename T1 = int, typename T2> class C2; //error。 //为函数模板指定默认模板参数 template<typename T1, typename T2 = int> //OK void Func2(T1 a, T2 b); template<typename T1, typename T2 = int> //OK,指定模板默认参数的顺序可任意! void Func3(T1 a, T2 b); //***************调用函数模板时模板参数的填充******************************* template <typename R = int, typename U> R func4(U val) { cout << "R‘s type is: "<< typeid(R).name() << ", U‘s type is: " << typeid(U).name() << endl; } //******************当默认模板参数遇到模板参数自动推导时******************* template <typename T> struct Identity //包装类,为定义模板的别名而增加的! { typedef T type; }; template <typename T = float> void func5(typename Identity<T>::type val, T t = 0) { cout << "val = " << val << typeid(val).name(); cout << ", t = " << t << typeid(T).name()<< endl; } int main() { func4(123); //R为int,U为int func4<long>(123); //调用时函数模板时,参数的填充从左往右的。即R为long, U为int func5(3.14, 0); //从第2个实参中推导出T的类型为int类型。(因为包装类模板禁止了val的自动推导) func5(3.14); //第2个参数使用默认模板参数类型,即T为默认的float类型 func5(123, 3.14); //第2个实参为double,推导出T为double类型 return 0; } /*测试结果: e:\Study\C++11\4>g++ test3.cpp -std=c++11 e:\Study\C++11\4>a.exe R‘s type is: i, U‘s type is: i R‘s type is: l, U‘s type is: i val = 3i, t = 0i val = 3.14f, t = 0f val = 123d, t = 3.14d */
以上是关于第4课 模板的细节改进的主要内容,如果未能解决你的问题,请参考以下文章