概念 (C++)

动机

模板类别和函数有必要的对他们使用的类型加上限制。例如STL容器要求它所包含的类型必须是可赋值的。不像动态多态所展现的类别继承阶级，接受Foo&类型的函数可以接受Foo的任何子类；只要支持所有模板内使用的操作，任何类别都可以被提供作为模版参数。对函数来说，引数的要求是明确的(必需是Foo的子类)；但是对模版来说，对象必须匹配的接口是不明确的。“概念”(concept)提供了一种机制，要求模板参数必须匹配特定条件。
引入 concept 的主要目的，是为了改善编译器发现问题代码所产生的错误消息。若程序员尝试在模板中使用不匹配其接口需求的类型，编译器应当回报错误。问题在于与模板使用相关的错误消息极难解读，尤其不利于新手。主要有两个原因：首先，错误消息往往将模板参数以原名全数列出，造成消息长度暴增。某些编译器甚至会对简单的错误产生数千字节的错误消息。其次，错误消息通常不会立即指出真正发生问题之处。例如，当程序员试图将不带有拷贝构造函数的类型置入vector中，第一个错误几乎总是指向vector内部使用拷贝建构之处。程序员必须有足够的经验和技巧才能够了解真正的错误，是由于使用的类型不满足vector类的要求(需要拷贝构造函数)。
为了解决上述的问题，C++0x 加入了concept 这种语言特性。Concept 是一种具名的构造，用来描述类型的需求或是条件限制。在 OOP 中，类似的做法是利用基底类别的定义，当作派生类的最小需求("is-a"的继承方式，派生类都带有基底类别的接口)。而 concept 的定义不限于作为模板参数的限制条件，也可以适用于模板定义(如最后的concept Stack)。
模板使用concept 的一种方法是以concept 名称取代模板类型指示字class或typename。在下面的例子中，若传入模板函数min的类型不满足concept LessThanComparable的要求，编译时将会产生错误，告知用户具现化(instantiate)模板的类型不匹配concept LessThanComparable。
template<LessThanComparable T>
  const T& min(const T &x, const T &y)
  {
    return y < x ? y : x;
  }
相较于上例的简式用法，更为泛用的concept使用形式如下：
template<typename T> requires LessThanComparable<T>
  const T& min(const T &x, const T &y)
  {
    return y < x ? y : x;
  }
泛用形中，使用关键字requires 作为类型需求表列的开始。需求表列由concept 所构成，可以利用"非"(!) 与 "且"(&&)的符号，将数个concept 结合，如同逻辑表达式。若用户想避免某个特定的concept 被模板套用，可以用这样的语法：requires !LessThanComparable<T>。在模板特化或偏特化中，可以指定类型使用特定的模板实现；而否定的concept 语法，可以显式地在模板或concept 中指明被排除的类型条件为何。另外，若需要在需求表列中表达"且"(logical-and)的语义，使用"&&"将多个concept 链接起来即可。例如若模板中的类型需要设值(assignment)以及拷贝建构(copy-construct)，可以使用requires Assignable<T>&&CopyConstructible<T>。

定义概念

定义 concept 的方式如下：
auto concept LessThanComparable<typename T>{
  bool operator<(T, T);}
此处为concept LessThanComparable 宣告，说明若类型T 有一个双参数的函数：operator <，且函数传回值为bool，则类型T 满足 concept LessThanComparable。函数 operator < 可以是全域或是成员函数。
C++0x 为了避免concept 的误用，除非用户显式指明，编译器不会主动认定类型匹配concept (隐式套用concept)。为了避免繁琐的指明，此处关键字auto 代表只要类型带有concept 中指定的操作，它即是匹配该concept 的一个类型。若没有加上auto，则必须使用concept_map来指明类型匹配特定的concept。
concept 也可以包含多种类型。例如以下的concept Convertible，表示类型T 可转换为U。
auto concept Convertible<typename T, typename U>{
  operator U(const T&);}
在模板中使用涉及多态别的concept，必须使用泛用形式：
template<typename U, typename T> requires Convertible<T, U>
  U convert(const T& t)
  {
    return t;
  }
Concept 可以是其他concept 的构件。在下例中，InputIterator 的第一个参数Iter 必须匹配concept Regular：
concept InputIterator<typename Iter, typename Value>{
  requires Regular<Iter>;
  Value operator*(const Iter&);
  Iter& operator++(Iter&);
  Iter operator++(Iter&, int);}
另一方面，concept 之间也能带有派生关系。如同类的继承，满足派生concept 的类型也必须满足基底concept，语法上也和类继承相同：
concept ForwardIterator<typename Iter, typename Value> : InputIterator<Iter, Value>{
  // 在此加上ForwardIterator 的其它要求}
Concept 中也可宣告关系类型(associated type)，以 typename 宣告。模板使用concept 时，模板引数必须要提供相关类型的定义。
concept InputIterator<typename Iter>{
  typename value_type;
  typename reference;
  typename pointer;
  typename difference_type;
  requires Regular<Iter>;
  requires Convertible<reference, value_type>;
  reference operator*(const Iter&); // 解參考
  Iter& operator++(Iter&); // 前置遞增
  Iter operator++(Iter&, int); // 後置遞增
  // ...}

映射概念

Concept map 可以将类型"映射"到特定的concept，告知编译器使用的类型是"如何"匹配 concept。
concept_map InputIterator<char*>{
  typedef char value_type ;
  typedef char& reference ;
  typedef char* pointer ;
  typedef std::ptrdiff_t difference_type ;};
这个 concept_map 定义 char* 匹配 concept InputIterator，并且一一声明所需的关系类型。
concept_map 可以宣告成模板，下面的例子声明所有的指针类型都匹配concept InputIterator。
template<typename T> concept_map InputIterator<T*>{
  typedef T value_type ;
  typedef T& reference ;
  typedef T* pointer ;
  typedef std::ptrdiff_t difference_type ;};
concept_map 可以作为一个迷你类型，在其中置入函数的定义与其它用来定义类的相关构件。
concept Stack<typename X>{
  typename value_type;
  void push(X&, const value_type&);
  void pop(X&);
  value_type top(const X&);
  bool empty(const X&);};template<typename T> concept_map Stack<std::vector<T> >{
  typedef T value_type;
  void push(std::vector<T>& v, const T& x) { v.push_back(x); }
  void pop(std::vector<T>& v) { v.pop_back(); }
  T top(const std::vector<T>& v) { return v.back(); }
  bool empty(const std::vector<T>& v) { return v.empty(); }};
在这里，concept Stack 定义了需要的函数以及关系类型，而 concept_map 定义如何以std::vector 实现底层的操作，每个concept Stack 里的函数都可以转接到std::vector 的函数调用。因此，concept_map能在不改变原类型(类别)的定义下， 完成接口转换(interface adaptation)。
最后值得一提的是，一些模板的要求可以使用编译期断言(static assertion)。它们可以验证一些模板的要求，不过实际上是针对不同的问题。

公设

C++0x 提供了公设(axiom) 用来表达概念的语义属性。举例来说，我们可以用公设Associativity 来定义概念Semigroup:
concept Semigroup< typename Op, typename T> : CopyConstructible<T>{
  T operator()(Op, T, T);

  axiom Associativity(Op op, T x, T y, T z)
  {
    op(x, op(y, z)) == op(op(x, y), z);
  }}
编译器可以利用公设所表达的语义做些原本不被允许的优化，因为这些优化可能会在程序可见的行为上有副作用(其除了少数的例外，其中之一是回返值优化(RVO))。在上述的例子中，编译器可能会重新安排operator() 调用的次序。前提是Op 和 T 与概念Semigroup 有映射关系。
公设也能在软件验证，软件测试以及其它程序分析和转换上有所帮助。