std::common_type - cppreference.com (original) (raw)
| | | | | -------------------------------------------- | | ------------- | | template< class... T > struct common_type; | | (since C++11) |
Determines the common type among all types T..., that is a type all T... can be explicitly converted to. If such a type exists (as determined according to the rules below), the member type names that type. Otherwise, there is no member type.
If sizeof...(T) is zero, there is no member
type.If sizeof...(T) is one (i.e.,
T...contains only one typeT0), the membertypenames the same type as std::common_type<T0, T0>::type if it exists; otherwise there is no membertype.If sizeof...(T) is two (i.e.,
T...contains exactly two typesT1andT2),If applying std::decay to at least one of
T1andT2produces a different type, the membertypenames the same type as std::common_type<std::decay<T1>::type, std::decay<T2>::type>::type, if it exists; if not, there is no membertype;Otherwise, if there is a user specialization for std::common_type<T1, T2>, that specialization is used;
Otherwise, if std::decay<decltype(false ? std::declval<T1>() : std::declval<T2>())>::type is a valid type, the member
typedenotes that type, see the conditional operator;
| Otherwise, if std::decay<decltype(false ? std::declval<CR1>() : std::declval<CR2>())>::type is a valid type, where CR1 and CR2 are const std::remove_reference_t<T1>& and const std::remove_reference_t<T2>& respectively, the member type denotes that type; | (since C++20) |
|---|
Otherwise, there is no member
type.If sizeof...(T) is greater than two (i.e.,
T...consists of the typesT1, T2, R...), then if std::common_type<T1, T2>::type exists, the membertypedenotes std::common_type<typename std::common_type<T1, T2>::type, R...>::type if such a type exists. In all other cases, there is no membertype.
If any type in the parameter pack T is not a complete type, (possibly cv-qualified) void, or an array of unknown bound, the behavior is undefined.
If an instantiation of a template above depends, directly or indirectly, on an incomplete type, and that instantiation could yield a different result if that type were hypothetically completed, the behavior is undefined.
Contents
- 1 Nested types
- 2 Helper types
- 3 Specializations
- 4 Possible implementation
- 5 Notes
- 6 Examples
- 7 Defect reports
- 8 See also
[edit] Nested types
| Name | Definition |
|---|---|
| type | the common type for all T |
[edit] Helper types
| template< class... T > using common_type_t = typename common_type<T...>::type; | | (since C++14) | | ------------------------------------------------------------------------------------ | | ------------- |
[edit] Specializations
Users may specialize common_type for types T1 and T2 if
- At least one of
T1andT2depends on a user-defined type, and - std::decay is an identity transformation for both
T1andT2.
If such a specialization has a member named type, it must be a public and unambiguous member that names a cv-unqualified non-reference type to which both T1 and T2 are explicitly convertible. Additionally, std::common_type<T1, T2>::type and std::common_type<T2, T1>::type must denote the same type.
A program that adds common_type specializations in violation of these rules has undefined behavior.
Note that the behavior of a program that adds a specialization to any other template (except for std::basic_common_reference)(since C++20) from <type_traits> is undefined.
The following specializations are already provided by the standard library:
[edit] Possible implementation
// primary template (used for zero types) template<class...> struct common_type {}; // one type template struct common_type : common_type<T, T> {}; namespace detail { template<class...> using void_t = void; template<class T1, class T2> using conditional_result_t = decltype(false ? std::declval() : std::declval()); template<class, class, class = void> struct decay_conditional_result {}; template<class T1, class T2> struct decay_conditional_result<T1, T2, void_t<conditional_result_t<T1, T2>>> : std::decay<conditional_result_t<T1, T2>> {}; template<class T1, class T2, class = void> struct common_type_2_impl : decay_conditional_result<const T1&, const T2&> {}; // C++11 implementation: // template<class, class, class = void> // struct common_type_2_impl {}; template<class T1, class T2> struct common_type_2_impl<T1, T2, void_t<conditional_result_t<T1, T2>>> : decay_conditional_result<T1, T2> {}; } // two types template<class T1, class T2> struct common_type<T1, T2> : std::conditional<std::is_same<T1, typename std::decay::type>::value && std::is_same<T2, typename std::decay::type>::value, detail::common_type_2_impl<T1, T2>, common_type<typename std::decay::type, typename std::decay::type>>::type {}; // 3+ types namespace detail { template<class AlwaysVoid, class T1, class T2, class... R> struct common_type_multi_impl {}; template<class T1, class T2, class...R> struct common_type_multi_impl<void_t<typename common_type<T1, T2>::type>, T1, T2, R...> : common_type<typename common_type<T1, T2>::type, R...> {}; } template<class T1, class T2, class... R> struct common_type<T1, T2, R...> : detail::common_type_multi_impl<void, T1, T2, R...> {};
[edit] Notes
For arithmetic types not subject to promotion, the common type may be viewed as the type of the (possibly mixed-mode) arithmetic expression such as T0() + T1() + ... + Tn().
[edit] Examples
Demonstrates mixed-mode arithmetic on a program-defined class:
#include #include template struct Number { T n; }; template<class T, class U> constexpr Number<std::common_type_t<T, U>> operator+(const Number& lhs, const Number& rhs) { return {lhs.n + rhs.n}; } void describe(const char* expr, const Number& x) { std::cout << expr << " is Number{" << x.n << "}\n"; } void describe(const char* expr, const Number& x) { std::cout << expr << " is Number{" << x.n << "}\n"; } int main() { Number i1 = {1}, i2 = {2}; Number d1 = {2.3}, d2 = {3.5}; describe("i1 + i2", i1 + i2); describe("i1 + d2", i1 + d2); describe("d1 + i2", d1 + i2); describe("d1 + d2", d1 + d2); }
Output:
i1 + i2 is Number{3} i1 + d2 is Number{4.5} d1 + i2 is Number{4.3} d1 + d2 is Number{5.8}
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 2141 | C++11 | the result type of the conditional operator was not decayed | decayed the result type |
| LWG 2408 | C++11 | common_type was not SFINAE-friendly | made SFINAE-friendly |
| LWG 2460 | C++11 | common_type specializations were nearly impossible to write | reduced the number ofspecializations needed |