namespace std {
template <class... Types>
struct common_type {
using type = …;
};
template <class... T>
using common_type_t = typename common_type<T...>::type; // C++14
}
概要
変換可能な共通の型を取得する。
要件
Types...
の全ての型は完全型であるか、const/volatile
修飾された(あるいはされていない)void
か、要素数不明の配列型でなければならない。
効果
common_type
は、Types...
に含まれる全ての型が暗黙変換可能な型を、メンバ型type
として定義する。
より詳細には、次のように決定される。ただし、C++11ではdecay
を適用するプロセスが、C++14では下記N == 2
の時のプロセスが、C++17ではN == 2
のときCOND-RES
を適用するプロセスが、それぞれ行われない。
N = sizeof...(Types)
として
-
N == 0
: メンバ型type
は定義されない。 -
N == 1
:Types...
内の唯一の型をT
とすると、type = common_type_t<T, T>;
のようにtype
を定義。 N == 2
:Types...
の1, 2番目の型をT1, T2
、D1 = decay_t<T1>, D2 = decay_t<T2>
としてT1,T2
に対するdecay
適用が少なくとも片方が恒等写像とならない(is_same_v<T1, D1> == false || is_same_v<T2, D2> == false
となる)場合、type = common_type_t<D1, D2>;
common_type<T1, T2>
に対するユーザ定義の特殊化が行われていれば、同特殊化を利用する。C = decay_t<decltype(false ? declval<D1>() : declval<D2>())>
が有効な型ならば、type = C;
COND-RES(CREF(D1), CREF(D2))
が有効な型ならば、type = decay_t<COND-RES(CREF(D1), CREF(D2))>;
- そうでなければ、メンバ型
type
は定義されない。
N >= 3
:Types...
の1、2番目の型をT1, T2
、残りのパラメータパックをP...
とすると、type = common_type_t<common_type_t<T1, T2>, P...>;
のようにtype
を定義。- 先頭2つの型の共通型を求めて、その型と3番目の型の共通型を求めて、その型と4番目の...というように再帰的に
common_type
を適用していく。
- 先頭2つの型の共通型を求めて、その型と3番目の型の共通型を求めて、その型と4番目の...というように再帰的に
2つの型T1, T2
に対するdecay
の適用がともに恒等写像となるのは以下の場合である。
T1, T2
はともに配列型ではなくT1, T2
はともに関数型でもなくT1, T2
はともに参照型でもなくT1, T2
はともにCV修飾もされていない
COND-RES
やCREF
はそれぞれ次のように定義される型を表す説明専用のものである。
CREF(X)
add_lvalue_reference_t<const remove_reference_t<A>>
COND-REF(X, Y)
decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()())
特殊化
common_type
は以下の条件を満たす場合に、2引数のもの(common_type<T1, T2>
)に限ってユーザー定義の特殊化が許可されている。
T1, T2
の少なくとも片方はプログラム定義型に依存している- プログラム定義型とは、標準ライブラリの型を除いた、ユーザーによって定義された型のこと
T1, T2
に対するdecay
の適用はともに恒等写像となる(上記参照)
そして、そのような特殊化は必ずしもメンバ型type
を持たなくても構わない。
もしtype
を定義する場合はpublic
にただ一つだけ定義し、その型はT1, T2
から明示的に変換可能であり、かつCV修飾されておらず参照型でもない型である必要がある。
そして、その特殊化はT1,T2
の引数順を入れ替えても同じ結果を返す(対称性を持つ)必要がある。
これらの規則に違反した特殊化を定義したとしてもコンパイルエラーにはならず、未定義動作となる。
このように定義されたユーザー定義の特殊化は、common_type_t<T1, T2>
のように使用された時T1, T2
がともにCV修飾もなく参照でもない場合は直接利用される。
T1, T2
のどちらかがCV修飾されているか参照である場合は、プライマリのcommon_type
によってdecay
された上で利用される。
なお、common_type, basic_common_reference
以外の<type_traits>
内テンプレートに対するユーザー定義の特殊化は許可されていない。
例
#include <iostream>
#include <type_traits>
// 2つの値どちらが小さいかを返すアルゴリズム
// 型Tと型Uの共通の型を戻り値型にする
template <class T, class U>
typename std::common_type<T, U>::type
generic_min(T t, U u)
{
return t < u ? t : u;
}
int main()
{
auto x = generic_min(3L, 2);
static_assert(
std::is_same<decltype(x), long>::value == true,
"type of x is long");
std::cout << x << std::endl;
}
出力
2
定義(C++11)
template <class ...T>
struct common_type;
template <class T>
struct common_type<T> {
using type = T;
};
template <class T, class U>
struct common_type<T, U> {
using type = decltype(true ? declval<T>() : declval<U>());
};
template <class T, class U, class... V>
struct common_type<T, U, V...> {
using type = typename common_type<typename common_type<T, U>::type, V...>::type;
};
定義(C++14)
template <class ...T>
struct common_type;
template <class... T>
using common_type_t = typename common_type<T...>::type;
template <class T>
struct common_type<T> {
using type = decay_t<T>;
};
template <class T, class U>
struct common_type<T, U> {
using type = decay_t<decltype(true ? declval<T>() : declval<U>())>;
};
template <class T, class U, class... V>
struct common_type<T, U, V...> {
using type = common_type_t<common_type_t<T, U>, V...>;
};
バージョン
言語
- C++11
処理系
- Clang: 3.0 ✅
- GCC: 4.4.7 ✅
- Visual C++: 2010 ✅, 2012 ✅, 2013 ✅, 2015 ✅
- 2012までは、可変引数テンプレートに対応していないため、不完全な実装である。
common_type_t
は、2013から。
参照
- N2661 A Foundation to Sleep On
- N3546 TransformationTraits Redux
- N3655 TransformationTraits Redux, v2
- LWG Issue 2141.
common_type
trait produces reference types- C++11では、
common_type
の結果が参照型になる場合があった。C++14でdecay_t
を通すことにしたことにより、参照型が返されることがなくなった。
- C++11では、
- P0453R1 Resolving LWG Issues re common_type
- P0898R3 Standard Library Concepts
- C++20で
COND-RES
,CREF
操作を利用するステップが追加された。
- C++20で