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のみを含む場合)、メンバtypeは std :: common_type < T0, T0 > :: type と同じ型を指す(存在する場合)。存在しない場合はメンバtypeは存在しない。 -
sizeof...
(
T
)
が2の場合(すなわち
T...が正確に2つの型T1とT2を含む場合)、
-
-
T1とT2の少なくとも一方に std::decay を適用した結果が元の型と異なる場合、メンバtypeは std :: common_type < std:: decay < T1 > :: type , std:: decay < T2 > :: 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 < typename std :: common_type < T1, T2 > :: type , R... > :: type を示す(そのような型が存在する場合)。それ以外の場合、メンバtypeは存在しない。
パラメータパック
T
内のいずれかの型が完全型でない場合((possibly cv-qualified)
void
または未知の境界を持つ配列である場合)、動作は未定義です。
上記のテンプレートのインスタンス化が、直接的または間接的に不完全型に依存しており、その型が仮に完全化された場合に異なる結果をもたらす可能性がある場合、その動作は未定義です。
目次 |
ネストされた型
| 名前 | 定義 |
type
|
すべての
T
に対する共通型
|
ヘルパー型
|
template
<
class
...
T
>
using common_type_t = typename common_type < T... > :: type ; |
(C++14以降) | |
特殊化
ユーザーは型
T1
と
T2
に対して
common_type
を特殊化することができます。
-
T1とT2の少なくとも一方がユーザー定義型に依存しており、かつ -
std::decay
が
T1とT2の両方に対して恒等変換である。
そのような特殊化が
type
というメンバを持つ場合、それは
T1
と
T2
の両方が明示的に変換可能な、CV修飾されていない非参照型を指す、公開かつ明確なメンバでなければなりません。さらに、
std
::
common_type
<
T1, T2
>
::
type
と
std
::
common_type
<
T2, T1
>
::
type
は同じ型を示さなければなりません。
これらの規則に違反して
common_type
の特殊化を追加するプログラムは未定義動作となります。
他のテンプレートに特殊化を追加するプログラムの動作は未定義であることに注意してください
(
std::basic_common_reference
を除く)
(C++20以降)
<type_traits>
から。
以下の特殊化は標準ライブラリによって既に提供されています:
|
std::common_type
特性を特殊化する
(クラステンプレートの特殊化) |
|
|
std::common_type
特性を特殊化する
(クラステンプレートの特殊化) |
|
|
(C++23)
|
2つの
pair
の共通型を決定する
(クラステンプレートの特殊化) |
|
(C++23)
|
tuple
と
tuple-like
型の共通型を決定する
(クラステンプレートの特殊化) |
イテレータと適応された
basic_const_iterator
型の共通型を決定する
(クラステンプレートの特殊化) |
実装例
// プライマリテンプレート (0個の型に対して使用) template<class...> struct common_type {}; // 1つの型 template<class T> struct common_type<T> : 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<T1>() : std::declval<T2>()); 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実装: // 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> {}; } // 2つの型 template<class T1, class T2> struct common_type<T1, T2> : std::conditional<std::is_same<T1, typename std::decay<T1>::type>::value && std::is_same<T2, typename std::decay<T2>::type>::value, detail::common_type_2_impl<T1, T2>, common_type<typename std::decay<T1>::type, typename std::decay<T2>::type>>::type {}; // 3つ以上の型 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...> {}; |
注記
プロモーションの対象とならない算術型の場合、共通型は以下のような(混合モードの可能性がある)算術式の型と見なすことができます: T0 ( ) + T1 ( ) + ... + Tn ( ) 。
例
プログラム定義クラスにおける混合モード算術演算の実演:
#include <iostream> #include <type_traits> template<class T> struct Number { T n; }; template<class T, class U> constexpr Number<std::common_type_t<T, U>> operator+(const Number<T>& lhs, const Number<U>& rhs) { return {lhs.n + rhs.n}; } void describe(const char* expr, const Number<int>& x) { std::cout << expr << " is Number<int>{" << x.n << "}\n"; } void describe(const char* expr, const Number<double>& x) { std::cout << expr << " is Number<double>{" << x.n << "}\n"; } int main() { Number<int> i1 = {1}, i2 = {2}; Number<double> 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); }
出力:
i1 + i2 is Number<int>{3}
i1 + d2 is Number<double>{4.5}
d1 + i2 is Number<double>{4.3}
d1 + d2 is Number<double>{5.8}
欠陥報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| LWG 2141 | C++11 | 条件演算子の結果型が decay されていなかった | 結果型を decay するように修正 |
| LWG 2408 | C++11 |
common_type
が SFINAE-friendly ではなかった
|
SFINAE-friendly に変更 |
| LWG 2460 | C++11 |
common_type
特殊化の実装がほぼ不可能だった
|
必要な特殊化の数を削減 |
関連項目
|
(C++20)
|
2つの型が共通の型を共有することを指定する
(コンセプト) |