std::common_type
ヘッダ <type_traits> で定義
|
||
template< class... T > struct common_type; |
(C++11以上) | |
型 T...
のすべてに共通の型、つまり、 T...
のいずれもが暗黙に変換できる型を調べます。 そのような型が存在するならば (以下のルールに従って決定されます)、メンバ type
はその型を表します。 そうでなければ、メンバ type
は存在しません。
- sizeof...(T) がゼロの場合、メンバ
type
は存在しません。 - sizeof...(T) が 1 の場合 (つまり
T...
が型T0
ひとつだけを含む場合)、 std::common_type<T0, T0>::type が存在するならばメンバtype
はそれと同じ型を表し、そうでなければメンバtype
は存在しません。 - sizeof...(T) が 2 の場合 (つまり
T...
がちょうど2個の型T1
およびT2
を含む場合)、
-
T1
とT2
の少なくとも一方に std::decay を適用すると異なる型が生成される場合、 std::common_type<std::decay<T1>::type, std::decay<T2>::type>::type が存在するならばメンバtype
はそれと同じ型を表し、そうでなければメンバtype
は存在しません。 - そうでなく、 std::common_type<T1, T2> に対するユーザの特殊化が存在する場合、その特殊化が使用されます。
- そうでなく、 std::decay<decltype(false ? std::declval<T1>() : std::declval<T2>())>::type が有効な型の場合、メンバ
type
はその型を表します。
-
|
(C++20以上) |
- そうでなければ、メンバ
type
は存在しません。
- そうでなければ、メンバ
- sizeof...(T) が 2 より大きい場合 (つまり
T...
が型T1, T2, R...
) から構成される場合)、 std::common_type<T1, T2>::type が存在するならば、メンバtype
は std::common_type<std::common_type<T1, T2>::type, R...>::type が存在すればその型を表します。 そうでなければメンバtype
は存在しません。
パラメータパック T
内の型 はいずれも完全型 (またはその cv 修飾された型)、 void、またはサイズの未知な配列でなければなりません。 そうでなければ、動作は未定義です。
上記のテンプレートの実体化が直接または間接的に不完全型に依存しており、もしその型が仮に完全型であったならばその実体化が異なる結果を産むであろう場合は、動作は未定義です。
目次 |
[編集] メンバ型
名前 | 定義 |
type
|
T... のすべてに対する共通の型
|
[編集] ヘルパー型
template< class... T > using common_type_t = typename common_type<T...>::type; |
(C++14以上) | |
[編集] 特殊化
以下の場合、ユーザは型 T1
および T2
に対して common_type
を特殊化しても構いません。
-
T1
とT2
の少なくとも一方がユーザ定義型に依存し、さらに -
T1
とT2
の両方に対して std::decay が恒等変換である。
そのような特殊化が type
という名前のメンバを持つ場合、それは T1
と T2
の両方が明示的に変換可能な、 cv 修飾されていない非参照型を表す、パブリックな曖昧でないメンバ型でなければなりません。 さらに、 std::common_type<T1, T2>::type と std::common_type<T2, T1>::type は同じ型を表さなければなりません。
これらのルールに違反する common_type
の特殊化を追加するプログラムは、未定義動作を持ちます。
common_type
以外の <type_traits>
で定義されているテンプレートに特殊化を追加するプログラムの動作は未定義であることに注意してください。
以下の特殊化は標準ライブラリによってあらかじめ提供されています。
std::common_type 特性の特殊化 (クラステンプレートの特殊化) | |
std::common_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() のような (型が混在しているかもしれない) 算術式の型としてみることができます。
[編集] 欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
LWG 2141 | C++11 | common_type<int, int>::type is int&& | decayed result type |
LWG 2408 | C++11 | common_type is not SFINAE-friendly
|
made SFINAE-friendly |
LWG 2460 | C++11 | common_type specializations are nearly impossible to write
|
reduced number of specializations needed |
[編集] 例
ユーザ定義クラスに対する型混在算術をデモンストレーションします。
#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