模板的右尖括号
在泛型编程中,模板实例化有一个非常繁琐的地方,那就是连续的两个右尖括号 >>
会被编译器解析成右移操作符,而不是模板参数表的结束。
先看一段关于容器遍历的代码,在创建的类模板 Base
中提供了遍历容器的操作函数 traversal()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream> #include <vector> using namespace std;
template <typename T> class Base { public: void traversal(T& t) { auto it = t.begin(); for (; it != t.end(); ++it) { cout << *it << " "; } cout << endl; } };
int main() { vector<int> v {1,2,3,4,5,6,7,8,9}; Base<vector<int>> b; b.traversal(v);
return 0; }
|
如果使用 C++98/03 标准来编译上边的这段代码,会得到错误提示如下:
1 2
| test.cpp:25:20: error: '>>' should be '> >' within a nested template argument list Base<vector<int>> b;
|
根据错误提示中描述模板的两个右尖括之间需要添加空格,这样写起来就非常的麻烦,C++11 改进了编译器的解析规则,尽可能地将多个右尖括号 >>
解析成模板参数结束符,方便编写模板相关的代码。
上面的这段代码,在支持 C++11 的编译器中编译是没有问题的,如果使用 g++ 直接编译需要加参数 -std=c++11:
默认模板参数
在 C++98/03 标准中,类模板可以有默认的模板参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> using namespace std;
template <typename T = int, T t = 520> class Test { public: void print() { cout << "current value: " << t << endl; } };
int main() { Test<> t; t.print();
Test<int, 1024> t1; t1.print();
return 0; }
|
但是不支持函数的默认模板参数,在 C++11 中添加了对函数模板默认参数的支持:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> using namespace std;
template <typename T = int> void func(T t) { cout << "current value: " << t << endl; }
int main() { func(100); return 0; }
|
上面的代码可知:当所有模板参数都有默认参数时,函数模板的调用像一个普通函数。
但对于类模板而言,就算所有参数都有默认参数,在使用时也必须在模板名后添加 <>
来实例化。
另外:函数模板的默认模板参数在使用规则上和其他的默认参数也有一些不同,它没有必须写在参数表最后的限制。
当默认模板参数和模板参数自动推导结合起来时,书写非常灵活。可以指定函数模板中的一部分模板参数使用默认参数,另一部分使用自动推导。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <string> using namespace std;
template <typename R = int, typename N> R func(N arg) { return arg; }
int main() { auto ret1 = func(520); cout << "return value-1: " << ret1 << endl;
auto ret2 = func<double>(52.134); cout << "return value-2: " << ret2 << endl;
auto ret3 = func<int>(52.134); cout << "return value-3: " << ret3 << endl;
auto ret4 = func<char, int>(100); cout << "return value-4: " << ret4 << endl;
return 0; }
|
当默认模板参数和模板参数自动推导同时使用时(优先级从高到低):
如果可以推导出参数类型,那么使用推导出的类型。
如果函数模板无法推导出参数类型,那么编译器会使用默认模板参数。
如果无法推导出模板参数类型并且没有设置默认模板参数,编译器就会报错。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <iostream> #include <string> using namespace std;
template <typename T, typename U = char> void func(T arg1 = 100, U arg2 = 100) { cout << "arg1: " << arg1 << ", arg2: " << arg2 << endl; }
int main() { func('a'); func(97, 'a'); return 0; }
|
参考资料
https://subingwen.cn/cpp/template