namespace std {
template <class... Types>
struct common_reference {
using type = …;
};
template <class... Types>
using common_reference_t = typename common_reference<Types...>::type;
}
概要
与えられた型を全て参照可能な、共通の参照型を取得する。
要件
Types...の全ての型は完全型であるか、const/volatile修飾された(あるいはされていない)voidでなければならない。
効果
Types...に含まれる全ての型を参照可能な参照型を、メンバ型typeとして定義する。ただし、typeは必ずしも参照型であるとは限らない。
より詳細には、次のように決定される。
N = sizeof...(Types)として
-
N == 0: メンバ型typeは定義されない。 -
N == 1:Types...内の唯一の型をTとすると、type = T; -
N == 2:Types...の1、2番目の型をT1, T2とするとT1, T2は共に参照型であり、COMMON-REF(T1, T2)が有効ならば、type = COMMON-REF(T1, T2);basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::typeが有効ならば、メンバ型typeはその型COND-RES(T1, T2)が有効ならば、type = COND-RES(T1, T2);common_type_t<T1, T2>が有効ならば、type = common_type_t<T1, T2>;- そうでなければ、メンバ型
typeは定義されない。
N >= 3:Types...の1、2番目の型をT1, T2、残りのパラメータパックをRest、C = common_reference<T1, T2>とすると- 型
Cが存在する場合、type = common_reference<C, Rest...>;のようにメンバ型typeを定義。 - そうでなければ、メンバ型
typeは定義されない。
- 型
COMMON-REFやXREFはそれぞれ次のように定義される型を表す説明専用のものである
XREF(A)- 参照ではなくCV修飾もされていない型
Uを引数に取り、Aの参照・CV修飾をそのままUにコピーした型を示すエイリアステンプレートT<U> - このような
T<U>は、basic_common_referenceの要件指定で使用される
- 参照ではなくCV修飾もされていない型
COND-RES(X, Y)decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()())
COPYCV(FROM, TO)- 型
FROMの最上位のCV修飾をそのままTOへコピーした型を示すエイリアス
- 型
COMMON-REF(A, B)X = remove_reference_t<A>,Y = remove_reference_t<B>として、以下のように定義されるA, Bが共に左辺値参照型の場合、COND-RES(COPYCV(X, Y) &, COPYCV(Y, X) &)が有効であり参照型ならばその型A, Bが共に右辺値参照型の場合、C = remove_reference_t<COMMON-REF(X, Y)>&&(1に委譲)が有効であり、is_convertible_v<A, C> && is_convertible_v<B, C> == trueならば、型CAが右辺値参照型でBが左辺値参照型の場合、D = COMMON-REF(const X&, Y&)(1に委譲)が有効であり、is_convertible_v<A, D> == trueならば、型DBが右辺値参照型でAが左辺値参照型の場合、COMMON-REF(B, A)として3に委譲- それ以外の場合及び、上位のいずれかによる結果として不適格な型が生成された場合は、
COMMON-REF(A, B)は不適格
備考
本メタ関数common_referenceは、より一般的なイテレータのvalue_typeとreferenceとの間の関係性を定義するために導入された。
ポインタ型やC++17までの標準ライブラリにおける普通のイテレータ型では、そのreference型はvalue_type&の別名として定義されるという関係性がある。そのため、value_typeとreferenceはどちらもconst左辺値参照を付加することでconst value_type&に変換できる(ことが期待される)。
しかし、C++20から追加されるrangeライブラリの元となったrange-v3ライブラリにおけるzip_view(標準ライブラリへはC++23で導入される)のプロキシイテレータのように、特殊なイテレータではそのような関係性が必ずしも成り立つとは限らない。
このような関係性を持つ型があるとジェネリックなアルゴリズムをより簡易に書くことができるようになるなどメリットがあるため、そのような型を求めるためにcommon_referenceが導入された。
他にも、2つの型の間で定義されるコンセプトにおいて、その2つの型の間で上記のような関係性が自然に要求される場合に、common_reference_withコンセプトを通じて利用される。
例
#include <string>
#include <vector>
#include <type_traits>
int main()
{
static_assert(std::same_as<std::common_reference_t<std::size_t&, int&>, std::size_t>);
static_assert(std::same_as<std::common_reference_t<const std::size_t&, int&>, std::size_t>);
static_assert(std::same_as<std::common_reference_t<long double&, double&>, long double>);
static_assert(std::same_as<std::common_reference_t<long double&, const double&>, long double>);
static_assert(std::same_as<std::common_reference_t<std::string&, std::string_view&>, std::string_view>);
static_assert(std::same_as<std::common_reference_t<const std::vector<int>, std::vector<int>&>, const std::vector<int>>);
}
出力
バージョン
言語
- C++20
処理系
- Clang: ??
- GCC: 10.1 ✅
- Visual C++: 2019 Update 3 ✅