我认为概念是一种元界面。他们根据能力对类型进行分类。下一个 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().
}
这是一种很好的可替代性。任何类型都符合遵循该概念的要求,而不仅仅是那些积极实现某些接口的类型。下一个 C++ 标准更进一步:它定义了一个Container
概念,该概念将适合普通数组(通过一些定义某些类型如何适合某些概念的缩放概念图)和其他现有的标准容器。
我提出这个的原因是因为我有一个模板化的容器,其中容器本身具有层次关系。我想编写使用这些容器的算法,而不关心它是哪个特定容器。此外,某些算法将受益于知道模板类型满足某些概念(例如,可比较)。
您实际上可以使用模板来做这两个。你可以保持你的层次关系来共享代码,然后以通用的方式编写算法。例如,传达您的容器具有可比性。这就像实现了标准的随机访问/转发/输出/输入迭代器类别:
// 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
每次启用或禁用不同的实现。