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的讨论。

posted @ 2020-09-14 22:38  失落孤舟  阅读(271)  评论(0编辑  收藏  举报