我认为概念是一种元界面。他们根据能力对类型进行分类。下一个 C++ 版本提供本地概念。直到我遇到 C++1x 的概念以及它们如何允许将不同但不相关的类型放在一起之前,我才理解它。假设你有一个Range 接口。您可以通过两种方式对其进行建模。一种是子类型关系:
class Range {
virtual Iterator * begin() = 0;
virtual Iterator * end() = 0;
virtual size_t size() = 0;
};
当然,从它派生的每个类都实现 Range 接口并且可以与您的函数一起使用。但现在你看到它是有限的。数组呢?这也是一个范围!
T t[N];
begin() => t
end() => t + size()
size() => N
遗憾的是,您不能从实现该接口的 Range 类派生数组。您需要一个额外的方法(重载)。那么第三方容器呢?您的库的用户可能希望将他们的容器与您的函数一起使用。但他不能改变他们容器的定义。在这里,概念开始发挥作用:
auto concept Range<typename T> {
typename iterator;
iterator T::begin();
iterator T::end();
size_t T::size();
}
现在,您说一下如果T 具有适当的成员函数可以实现的某种类型的受支持操作。在您的库中,您将编写函数泛型。这允许您接受任何类型只要它支持所需的操作:
template<Range R>
void assign(R const& r) {
... iterate from r.begin() to r.end().
}
这是一种很好的可替代性。 Any 类型将符合遵循该概念的要求,而不仅仅是那些积极实现某些接口的类型。下一个 C++ 标准更进一步:它定义了一个 Container 概念,该概念将适合普通数组(通过定义某些类型如何适合某些概念的称为 concept map 的东西)和其他现有的 标准容器。
之所以提出这个问题,是因为我有一个模板化容器,其中容器本身具有层级关系。我想编写使用这些容器的算法,而不关心它是哪个特定容器。此外,某些算法会受益于知道模板类型满足某些概念(例如 Comparable)。
您实际上可以同时使用模板。你可以保持你的层次关系来共享代码,然后以通用的方式编写算法。例如,传达您的容器具有可比性。这就像实现了标准的随机访问/转发/输出/输入迭代器类别:
// tag types for the comparator cagetory
struct not_comparable { };
struct basic_comparable : not_comparable { };
template<typename T>
class MyVector : public BasicContainer<T> {
typedef basic_comparable comparator_kind;
};
/* Container concept */
T::comparator_kind: comparator category
实际上,这是一种合理简单的方法。现在您可以调用一个函数,它将转发到正确的实现。
template<typename Container>
void takesAdvantage(Container const& c) {
takesAdvantageOfCompare(c, typename Container::comparator_kind());
}
// implementation for basic_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, basic_comparable) {
...
}
// implementation for not_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, not_comparable) {
...
}
实际上可以使用不同的技术来实现它。另一种方法是每次使用boost::enable_if 启用或禁用不同的实现。