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>)に限ってユーザー定義の特殊化が許可されている。
そして、そのような特殊化は必ずしもメンバ型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_typetrait produces reference types- C++11では、
common_typeの結果が参照型になる場合があった。C++14でdecay_tを通すことにしたことにより、参照型が返されることがなくなった。
- C++11では、
- P0435R1 Resolving LWG Issues re common_type
- P0898R3 Standard Library Concepts
- C++20で
COND-RES,CREF操作を利用するステップが追加された。
- C++20で