C++ Templates (2.3 类模板的局部使用 Partial Usage of Class Templates)
2.3 类模板的局部使用 Partial Usage of Class Templates
类模板通常在它实例化的模板实参上进行多种操作(包括构造和析构),这给人一种印象:模板实参必须提供所有类模板的所有成员函数的所有操作。但是事实并非如此:模板实参仅需提供必要的操作而非可能需要的操作。
比如说,如果类Stack<>
提供一个成员函数printOn()
用于打印整个stack的内容,并对每个元素调用operator<<
:
template <typename T>
class Stack
{
...
void printOn(std::ostream& strm) const
{
for(T const& elem: elems)
{
strm << elem << ' '; //每个元素调用<<
}
}
}
但这依然可以使用没有定义operator<<
的类作为该类模板的模板实参:
Stack<std::pair<int,int>> ps; //注意: std::pair<>没有定义operator<<
ps.push({4, 5}); //OK
ps.push({6,7}); //OK
std::cout << ps.top().first << '\n'; //OK
std::cout << ps.top().second << '\n'; //OK
只有当调用这样的stack的printOn()
方法时,该代码才会生成错误,因为它不能实例化对该特殊类型的operator<<
的调用:
ps.printOn(std::cout); //ERROR: 元素类型不支持operator<<
2.3.1 Concepts
这引发了一个问题,如何知道哪些是模板实例化所需要的操作?术语概念(Concept)用于指示约束条件的集合,并在模板库中重复使用。比如,C++标准库依赖于随机访问迭代器(random access iterator)和默认构造(default constructible)。
当前(C++17),concepts只能或多或少地在文档中进行表述(比如代码注释)。这可能是个重要的问题,因为未遵循约束条件的错误可能引起恶心的错误消息(详见第9.4节)。
许多年来,有许多方法和试验来支持concepts的定义和验证,将其作为语言特性。然而,截止C++17还没有标准化的方法。
自从C++11以后,至少可以通过使用static_assert
关键字和预定义的类型特性来检查基本的约束条件,比如:
template <typename T>
class C
{
static_assert(std::is_default_constructible<T>::value, "Class C requires default-constructible elements");
...
}
没有该断言,如果需要默认构造函数,编译依然会失败。然而,该错误信息可能包含整个模板实例化的历史,从开始实例化到真实的模板定义(即错误检测到的地方,详见9.4节)。
然而,更多复杂的代码需要检查,比如,类型T的对象提供一种特殊的成员函数或者他们可以使用操作<进行比较。详见19.6.3节的一个详细的代码例程。
参考附件E关于更多的有关C++ Concept的讨论。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步