std::common_type - cppreference.com
型 T... のすべてに共通の型、つまり、 T... のいずれもが暗黙に変換できる型を調べます。 そのような型が存在するならば (以下のルールに従って決定されます)、メンバ type はその型を表します。 そうでなければ、メンバ type は存在しません。
パラメータパック T 内の型 はいずれも完全型 (またはその cv 修飾された型)、 void、またはサイズの未知な配列でなければなりません。 そうでなければ、動作は未定義です。
上記のテンプレートの実体化が直接または間接的に不完全型に依存しており、もしその型が仮に完全型であったならばその実体化が異なる結果を産むであろう場合は、動作は未定義です。
そのような特殊化が type という名前のメンバを持つ場合、それは T1 と T2 の両方が明示的に変換可能な、 cv 修飾されていない非参照型を表す、パブリックな曖昧でないメンバ型でなければなりません。 さらに、 std::common_type<T1, T2>::type と std::common_type<T2, T1>::type は同じ型を表さなければなりません。
// primary template (used for zero types) template <class ...T> struct common_type {}; //////// one type template <class T> struct common_type<T> : common_type<T, T> {}; //////// two types // default implementation for two types template<class T1, class T2> using cond_t = decltype(false ? std::declval<T1>() : std::declval<T2>()); template<class T1, class T2, class=void> struct common_type_2_default {}; template<class T1, class T2> struct common_type_2_default<T1, T2, std::void_t<cond_t<T1, T2>>> { using type = std::decay_t<cond_t<T1, T2>>; }; // dispatcher to decay the type before applying specializations template<class T1, class T2, class D1 = std::decay_t<T1>, class D2=std::decay_t<T2>> struct common_type_2_impl : common_type<D1, D2> {}; template<class D1, class D2> struct common_type_2_impl<D1, D2, D1, D2> : common_type_2_default<D1, D2> {}; template <class T1, class T2> struct common_type<T1, T2> : common_type_2_impl<T1, T2> { }; //////// 3+ types 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<std::void_t<common_type_t<T1, T2>>, T1, T2, R...> : common_type<common_type_t<T1, T2>, R...> { }; template <class T1, class T2, class... R> struct common_type<T1, T2, R...> : common_type_multi_impl<void, T1, T2, R...> { };
整数拡張の対象でない算術型の場合、 common_type は T0() + T1() + ... + Tn() のような (型が混在しているかもしれない) 算術式の型としてみることができます。
ユーザ定義クラスに対する型混在算術をデモンストレーションします。
#include <iostream> #include <type_traits> template <class T> struct Number { T n; }; template <class T, class U> Number<typename std::common_type<T, U>::type> operator+(const Number<T>& lhs, const Number<U>& rhs) { return {lhs.n + rhs.n}; } int main() { Number<int> i1 = {1}, i2 = {2}; Number<double> d1 = {2.3}, d2 = {3.5}; std::cout << "i1i2: " << (i1 + i2).n << "\ni1d2: " << (i1 + d2).n << '\n' << "d1i2: " << (d1 + i2).n << "\nd1d2: " << (d1 + d2).n << '\n'; }
出力:
i1i2: 3 i1d2: 4.5 d1i2: 4.3 d1d2: 5.8