| Home | Libraries | People | FAQ | More

### common_type

Header: `#include <boost/type_traits/common_type.hpp>` or `#include <boost/type_traits.hpp>`

    namespace boost {
      template <class... T> struct common_type;
      template<class... T> using common_type_t = typename common_type<T...>::type; // C++11 and above
    }

`common_type` is a traits class used to deduce a type common to a several types, useful as the return type of functions operating on multiple input types such as in mixed-mode arithmetic..

The nested typedef `::type` could be defined as follows:

    template <class... T>
    struct common_type;

    template <class T, class U, class... V>
    struct common_type<T, U, V...> {
        typedef typename common_type<typename common_type<T, U>::type, V...>::type type;
    };

    template <>
    struct common_type<> {
    };

    template <class T>
    struct common_type<T> {
        typedef typename decay<T>::type type;
    };

    template <class T, class U>
    struct common_type<T, U> {
        typedef typename decay<
            decltype( declval<bool>()?
                declval<typename decay<T>::type>():
                declval<typename decay<U>::type>() )
        >::type type;
    };

All parameter types must be complete. This trait is permitted to be specialized by a user if at least one template parameter is a user-defined type. Note: Such specializations are required when only explicit conversions are desired among the `common_type` arguments.

Note that when the compiler does not support variadic templates (and the macro `BOOST_NO_CXX11_VARIADIC_TEMPLATES` is defined) then the maximum number of template arguments is 9.

##### Tutorial

In a nutshell, `common_type` is a trait that takes 1 or more types, and returns a type which all of the types will convert to. The default definition demands this conversion be implicit. However the trait can be specialized for user-defined types which want to limit their inter-type conversions to explicit, and yet still want to interoperate with the `common_type` facility.

Example:

    template <class T, class U>
    complex<typename common_type<T, U>::type>
    operator+(complex<T>, complex<U>);

In the above example, "mixed-mode" complex arithmetic is allowed. The return type is described by `common_type`. For example the resulting type of adding a `complex<float>` and `complex<double>` might be a `complex<double>`.

Here is how someone might produce a variadic comparison function:

    template <class ...T>
    typename common_type<T...>::type
    min(T... t);

This is a very useful and broadly applicable utility.

##### How to get the common type of types with explicit conversions?

Another choice for the author of the preceding operator could be

    template <class T, class U>
    typename common_type<complex<T>, complex<U> >::type
    operator+(complex<T>, complex<U>);

As the default definition of `common_type` demands the conversion be implicit, we need to specialize the trait for complex types as follows.

    template <class T, class U>
    struct common_type<complex<T>, complex<U> > {
        typedef complex< common_type<T, U> > type;
    };

##### How important is the order of the `common_type<>` template arguments?

The order of the template parameters is important.

`common_type<A,B,C>::type` is not equivalent to `common_type<C,A,B>::type`, but to `common_type<common_type<A,B>::type, C>::type`.

Consider

    struct A {};
    struct B {};
    struct C {
        C() {}
        C(A const&) {}
        C(B const&) {}
        C& operator=(C const&) {
            return *this;
        }
    };

The following doesn't compile

    typedef boost::common_type<A, B, C>::type ABC; // Does not compile

while

    typedef boost::common_type<C, A, B>::type ABC;

compiles.

Thus, as `common_type<A,B>::type` is undefined, `common_type<A,B,C>::type` is also undefined.

It is intended that clients who wish for `common_type<A, B>` to be well defined to define it themselves:

    namespace boost
    {

    template <>
    struct common_type<A, B> {typedef C type;};

    }

Now this client can ask for `common_type<A, B, C>` (and get the same answer).

Clients wanting to ask `common_type<A, B, C>` in any order and get the same result need to add in addition:

    namespace boost
    {

    template <> struct common_type<B, A>
    : public common_type<A, B> {};

    }

This is needed as the specialization of `common_type<A, B>` is not be used implicitly for `common_type<B, A>`.

##### Can the `common_type` of two types be a third type?

Given the preceding example, one might expect `common_type<A,B>::type` to be `C` without any intervention from the user. But the default `common_type<>` implementation doesn't grant that. It is intended that clients who wish for `common_type<A, B>` to be well defined to define it themselves:

    namespace boost
    {

    template <>
    struct common_type<A, B> {typedef C type;};

    template <> struct common_type<B, A>
    : public common_type<A, B> {};

    }

Now this client can ask for `common_type<A, B>`.

##### How does `common_type` behave with pointers?

Consider

    struct C { }:
    struct B : C { };
    struct A : C { };

Shouldn't `common_type<A*,B*>::type` be `C*`? I would say yes, but the default implementation will make it ill-formed.

The library could add a specialization for pointers, as

    namespace boost
    {

        template <typename A, typename B>
        struct common_type<A*, B*> {
            typedef common_type<A, B>* type;
        };
    }

But in the absence of a motivating use cases, we prefer not to add more than the standard specifies.

Of course the user can always make this specialization.

##### Can you explain the pros/cons of `common_type` against Boost.Typeof?

Even if they appear to be close, `common_type` and `typeof` have different purposes. You use `typeof` to get the type of an expression, while you use `common_type` to set explicitly the type returned of a template function. Both are complementary, and indeed `common_type` is approximately equivalent to `decltype(declval<bool>() ? declval<T>() : declval<U>())`.

`common_type` is also similar to `promote_args<class ...T>` in `boost/math/tools/promotion.hpp`, though it is not exactly the same as `promote_args` either. `common_type<T1, T2>::type` simply represents the result of some operation on `T1` and `T2`, and defaults to the type obtained by putting `T1` and `T2` into a conditional statement.

It is meant to be customizable (via specialization) if this default is not appropriate.