名前空間
変種
操作

std::common_type

提供: cppreference.com
< cpp‎ | types
 
 
ユーティリティライブラリ
汎用ユーティリティ
日付と時間
関数オブジェクト
書式化ライブラリ (C++20)
(C++11)
関係演算子 (C++20で非推奨)
整数比較関数
(C++20)
スワップと型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
一般的な語彙の型
(C++11)
(C++17)
(C++17)
(C++17)
(C++17)

初等文字列変換
(C++17)
(C++17)
 
型サポート
型の性質
(C++11)
(C++11)
(C++14)
(C++11)
(C++11)(C++20未満)
(C++11)(C++20で非推奨)
(C++11)
型特性定数
メタ関数
(C++17)
定数評価文脈
サポートされている操作
関係と性質の問い合わせ
型変更
(C++11)(C++11)(C++11)
型変換
(C++11)
(C++11)
(C++17)
common_type
(C++11)
(C++11)(C++20未満)(C++17)
 
ヘッダ <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 を含む場合)、
  • T1T2 の少なくとも一方に 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 はその型を表します。
  • そうでなく、 std::decay<decltype(false ? std::declval<const T1 &>() : std::declval<const T2 &>())>::type が有効な型の場合、メンバ type はその型を表します。
(C++20以上)
  • そうでなければ、メンバ type は存在しません。
  • sizeof...(T) が 2 より大きい場合 (つまり T... が型 T1, T2, R...) から構成される場合)、 std::common_type<T1, T2>::type が存在するならば、メンバ typestd::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 を特殊化しても構いません。

  • T1T2 の少なくとも一方がユーザ定義型に依存し、さらに
  • T1T2 の両方に対して std::decay が恒等変換である。

そのような特殊化が type という名前のメンバを持つ場合、それは T1T2 の両方が明示的に変換可能な、 cv 修飾されていない非参照型を表す、パブリックな曖昧でないメンバ型でなければなりません。 さらに、 std::common_type<T1, T2>::typestd::common_type<T2, T1>::type は同じ型を表さなければなりません。

これらのルールに違反する common_type の特殊化を追加するプログラムは、未定義動作を持ちます。

common_type 以外の <type_traits> で定義されているテンプレートに特殊化を追加するプログラムの動作は未定義であることに注意してください。

以下の特殊化は標準ライブラリによってあらかじめ提供されています。

std::common_type 特性の特殊化
(クラステンプレートの特殊化) [edit]
std::common_type 特性の特殊化
(クラステンプレートの特殊化) [edit]

[編集] 実装例

// 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