最終更新日時(UTC):
が更新

履歴 編集

class template
<type_traits>

std::common_type(C++11)

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, T2D1 = 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つの型T1, T2に対するdecayの適用がともに恒等写像となるのは以下の場合である。

  • T1, T2はともに配列型ではなく
  • T1, T2はともに関数型でもなく
  • T1, T2はともに参照型でもなく
  • T1, T2はともにCV修飾もされていない

COND-RESCREFはそれぞれ次のように定義される型を表す説明専用のものである。

  • 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から。

参照