Update documentation of common_type a bit.

This commit is contained in:
Peter Dimov
2015-06-08 00:39:05 +03:00
parent 987b01b28c
commit 2180399398

View File

@ -11,83 +11,73 @@
[section:common_type common_type]
[/===================================================================]
[def __declval [@../../../utility/doc/html/declval.html declval]]
__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> struct common_type;
}
__common_type is a traits class used to deduce a type common to a several types, useful as the return type of functions
`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>
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 <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 T type;
typedef typename __decay<T>::type type;
};
template <class T, class U>
struct common_type<T, U> {
typedef decltype(__declval<bool>() ? __declval<T>() : __declval<U>()) type;
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.
are desired among the `common_type` arguments.
Note that when the compiler does not support variadic templates (and the macro BOOST_NO_VARIADIC_TEMPLATES is defined)
then the maximum number of template arguments is 3.
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.
[h4 Configuration macros]
When the compiler does not support static assertions then the user can select the way static assertions are reported. Define
* BOOST_COMMON_TYPE_USES_STATIC_ASSERT: define it if you want to use Boost.StaticAssert
* BOOST_COMMON_TYPE_USES_MPL_ASSERT: define it if you want to use Boost.MPL static assertions
The default behavior is to use mpl assertions in this case, but setting BOOST_COMMON_TYPE_USES_STATIC_ASSERT may reduce
compile times and header dependencies somewhat.
Depending on the static assertion used you will have an hint of the failing assertion either through the symbol or through the text.
When possible common_type is implemented using `decltype`. Otherwise when BOOST_COMMON_TYPE_DONT_USE_TYPEOF is not defined
it uses Boost.TypeOf.
[h4 Tutorial]
In a nutshell, __common_type is a trait that takes 1 or more types, and returns a type which
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.
and yet still want to interoperate with the `common_type` facility.
[*Example:]
template <class T, class U>
complex<typename __common_type<T, U>::type>
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.
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
typename common_type<T...>::type
min(T... t);
This is a very useful and broadly applicable utility.
@ -97,17 +87,17 @@ This is a very useful and broadly applicable utility.
Another choice for the author of the preceding operator could be
template <class T, class U>
typename __common_type<complex<T>, complex<U> >::type
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.
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;
struct common_type<complex<T>, complex<U> > {
typedef complex< common_type<T, U> > type;
};
[h4 How important is the order of the common_type<> template arguments?]
[h4 How important is the order of the `common_type<>` template arguments?]
The order of the template parameters is important.
@ -164,7 +154,7 @@ Clients wanting to ask `common_type<A, B, C>` in any order and get the same resu
This is needed as the specialization of `common_type<A, B>` is not be used implicitly for `common_type<B, A>`.
[h4 Can the common_type of two types be a third type?]
[h4 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>`
@ -183,7 +173,7 @@ to be well defined to define it themselves:
Now this client can ask for `common_type<A, B>`.
[h4 How common_type behaves with pointers?]
[h4 How does `common_type` behave with pointers?]
Consider
@ -209,17 +199,17 @@ But in the absence of a motivating use cases, we prefer not to add more than the
Of course the user can always make this specialization.
[h4 Can you explain the pros/cons of common_type against Boost.Typeof?]
[h4 Can you explain the pros/cons of `common_type` against Boost.Typeof?]
Even if they appear to be close, `__common_type` and `typeof` have
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 equivalent to
`decltype(__declval<bool>() ? __declval<T>() : __declval<U>())`
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.
`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.