4 - 默认模板参数
本文主要介绍了默认模板参数,以及如何在类模板和函数模板上使用它,最后还介绍了decltype()
关键字。
介绍
在定义模板时,除了可以定义类型T,还能定义一些模板参数。例如在构造一个vector
时,我们实际上使用了它的默认分配器。
使用
函数模板
默认模板参数就和普通函数的默认参数一样,一旦一个参数有了默认参数,它之后的参数都必须有默认参数。
给刚刚写的函数模板加一个默认参数:
using func_type = std::function<void(int&)>;
template<typename iter_type, typename func_type = func_type>
void for_each(iter_type first, iter_type last, func_type func = [](int& elem) {
++elem;
})
{
for (auto iter = first; iter != last; ++iter)
{
func(*iter);
}
}
然后就能不指定第三个参数直接用了:
mystd::for_each(ivec.begin(), ivec.end());
类模板
也很简单,例如可以效仿std::vector
,给自己的vector
也加一个allocator
:
template<typename T, typename allocator_type = std::allocator<T>>
class MyVector
{
public:
template<typename T2>
void outPut(const T2& elem);
};
// 类外定义
template<typename T, typename allocator_type>
template<typename T2>
void MyVector<T, allocator_type>::outPut(const T2& elem)
{
std::cout << elem << std::endl;
}
decltype关键字
有个比较大小的函数模板:
template <typename T1, typename T2, typename RT>
RT max(const T1& a, const T2& b)
{
return a > b ? a : b;
}
此时使用它会报错(例如max(1, 1.2)
),因为编译器可以推导出T1和T2的类型,但RT的类型无法推导出来。因此可以给RT一个默认模板参数(如 RT = double
)以“解决”问题,但这种代码必然没有鲁棒性,如果比较的是字符串呢。
这时候 decltype
便派上用场,该关键字可以获取表达式的类型,由于它是不求值操作数,会让括号内的东西不会被求值,所以不必担心效率问题:
template <typename T1, typename T2, typename RT = decltype(true ? T1{} : T2{})>
RT max(const T1& a, const T2& b)
{
return a > b ? a : b;
}
如上述代码所示,decltype
尝试获取表达式true ? T1{} : T2{}
的类型,这里利用到三目表达式的类型返回规则,会 返回T1和T2的公共类型(例如int和double会返回double)。其实这段代码还是有缺点的,例如这里的T1和T2类型如果没有默认构造函数就会报错,在后面的文章会用到std::declval
来优化这一点。
上面那一堆模板参数很长,有没有什么简便的方法:
C++11的后置返回类型:
template <typename T1, typename T2> auto max(const T1& a, const T2& b) -> decltype(true ? a : b) // 这里auto只是占位符, 不起实际作用 { return a > b ? a : b; }
使用这一特性的好处就是不用再“构造”两个对象了,可以直接用a和b,并且代码量少了也会舒服点。但需要注意的是,这里和上面的返回类型是不一样的,上面的是简单的T1/T2,而这里返回的是 const T1/T2&。
C++14的返回类型推导 + C++20的简写函数模板:
decltype(auto) max(const auto& a, const auto& b) { return a > b ? a : b; }
这种写法更精简了,注意这里的返回值
decltype(auto)
,如果是auto
,就遵循默认的模板参数推导规则,返回T类型;如果是decltype(auto)
,则返回T&类型。
参考资料
- 飘零的落花 - 现代C++详解
- Mq-b/Modern-Cpp-templates-tutorial: 现代C++模板教程 (github.com)
- C++20高级编程