| Home | Libraries | People | FAQ | More

## Concept Definitions

A Concept defines a set of constraints on the types that are stored in an `any`.

There are three kinds of concepts.

1. The library defines a number of predefined concepts. Most of these are equivalent to user-defined concepts, but a few require special handling.
2. Users can define their own primitive concepts as described below. The macros `BOOST_TYPE_ERASURE_MEMBER` and `BOOST_TYPE_ERASURE_FREE` define concepts of this form.
3. Any MPL Forward Sequence whose elements are concepts is also a concept. This allows concepts to be composed easily.

Each primitive concept defines a single function. A primitive concept must be a specialization of a class template, with a static member function called `apply`, which will be executed when the function is dispatched by `call`. The template can only take template type parameters. non-type template parameters and template template parameters are not allowed.

The template parameters of the concept may involve placeholders. The following are considered.

- Each template argument may be a cv and/or reference qualified placeholder type.
- If a template argument is a function type, its arguments and return type may be cv/reference qualified placeholders.

Any other placeholders are ignored.

A concept is instantiated by constructing an `any` from a raw value or by constructing a `binding`. When a concept is instantiated with a specific set of type bindings, each placeholder is bound to a cv-unqualified non-reference type. After replacing each placeholder in the template argument list with the type that it binds to, the following must hold.

- The number of arguments of apply in the bound concept must be the same as the number of arguments in the unbound concept.
- The arguments and return type of apply in the bound concept can be derived from the corresponding arguments and the return type in the unbound concept as follows: If the argument in the unbound concept is a placeholder with optional cv and reference qualifiers, then the argument in the bound concept can be found by replacing the placeholder. Otherwise, the argument in the unbound concept must be the same as the argument in the bound concept.

    // Correct.
    template<class T = _self>
    struct foo1 {
      static void apply(const T& t) { t.foo(); }
    };

    // Wrong.  The signature of apply is different from the
    // primary template
    template<>
    struct foo1<int> {
      static void apply(int i);
    };

    // Wrong.  A concept must be a template
    struct foo2 {
      static void apply(const _self&);
    };

    // Wrong. apply must be static
    template<class T = _self>
    struct foo3 {
      void apply(const T&);
    };

    // Wrong.  apply cannot be overloaded
    template<class T = _self>
    struct foo3 {
      static void apply(T&);
      static void apply(const T&);
    };

    // Wrong.  Only top level placeholders are detected
    template<class T>
    struct foo4;
    template<class T>
    struct foo4<boost::mpl::vector<T> > {
      static void apply(const T&);
    };

    // Wrong.  Template template parameters are not allowed.
    template<template<class> class T>
    struct foo5
    {
        static void apply(T<int>&);
    };