types_common_reference

types_common_reference (공통 참조 타입)

std::common_reference는 C++20부터 사용할 수 있는 타입 특성 템플릿이에요. 주어진 타입들 T... 모두가 변환되거나 바인딩될 수 있는 공통 참조 타입을 결정해요. 조건부 연산자와 비슷한 방식으로 동작해서, 여러 타입이 함께 쓰일 때 자연스러운 공통 타입을 찾는 데 유용해요.

출처: cppreference

본문

헤더 <type_traits>에 정의됨
template < class ... T > struct common_reference ; (C++20부터)

T...의 공통 참조 타입, 즉 T...의 모든 타입이 변환되거나 바인딩될 수 있는 타입을 결정해요. 아래 규칙에 따라 그러한 타입이 존재하면 멤버 타입 type이 그 타입을 가리켜요. 그렇지 않으면 멤버 타입 type은 존재하지 않아요. T... 중 어떤 타입이 (cv 한정된 void를 제외한) 불완전 타입이면 동작은 정의되지 않아요.

참조 타입이 주어졌을 때, common_reference는 주어진 참조 타입들이 모두 바인딩될 수 있는 참조 타입을 찾으려고 해요. 하지만 그러한 참조 타입을 찾지 못하면 비참조 타입을 반환할 수도 있어요.

  • sizeof...(T)가 0이면 멤버 타입 type은 없어요.
  • sizeof...(T)가 1이면 (즉 T...에 오직 하나의 타입 T0만 있으면) 멤버 타입 typeT0와 같은 타입을 가리켜요.
  • sizeof...(T)가 2이면 (즉 T...에 두 타입 T1, T2가 있으면): ST1T2의 단순 공통 참조 타입(simple common reference type)이라고 해요. 아래 조건이 모두 만족되면 멤버 타입 typeS를 가리켜요:
    • T1T2가 모두 참조 타입이고 S가 잘 형성되었을 것
std::is_convertible_v<std::add_pointer_t<T1>, std::add_pointer_t<S>>std::is_convertible_v<std::add_pointer_t<T2>, std::add_pointer_t<S>>가 모두 true일 것 (C++23부터)
  • 그렇지 않고, std::basic_common_reference<std::remove_cvref_t<T1>, std::remove_cvref_t<T2>, T1Q, T2Q>::type이 존재하면 (여기서 TiQTi의 cv 한정자와 참조 한정자를 U에 더하는 단항 별칭 템플릿, 즉 TiQ<U>UTi의 cv 및 참조 한정자를 추가한 타입), 멤버 타입 type은 그 타입을 가리켜요.
  • 그렇지 않고, decltype(false ? val<T1>() : val<T2>())가 유효한 타입이면 (여기서 val은 함수 템플릿 template <class T> T val();), 멤버 타입 type은 그 타입을 가리켜요.
  • 그렇지 않고, std::common_type_t<T1, T2>가 유효한 타입이면 멤버 타입 type은 그 타입을 가리켜요.
  • 그렇지 않으면 멤버 타입 type은 없어요.
  • sizeof...(T)가 2보다 크면 (즉 T...T1, T2, R...으로 구성되면), std::common_reference_t<T1, T2>가 존재할 때, std::common_reference_t<std::common_reference_t<T1, T2>, R...>가 존재하면 멤버 타입 type은 그 타입을 가리켜요. 그 외의 모든 경우에는 멤버 타입 type이 없어요.

두 참조 타입 T1T2의 단순 공통 참조 타입은 다음과 같이 정의돼요.

  • T1cv1 X&이고 T2cv2 Y&이면 (즉 둘 다 lvalue 참조 타입): 단순 공통 참조 타입은 decltype(false ? std::declval<cv12 X&>() : std::declval<cv12 Y&>())이에요. 여기서 cv12cv1cv2의 합집합이에요. 이 타입이 존재하고 참조 타입이면 그 타입이 단순 공통 참조 타입이 돼요.
  • T1T2가 모두 rvalue 참조 타입이면: T1&T2&의 단순 공통 참조 타입(이전 항목에 따라 결정)이 존재한다면, 그 타입에 대응하는 rvalue 참조 타입을 C라고 해요. std::is_convertible_v<T1, C>std::is_convertible_v<T2, C>가 모두 true이면 T1T2의 단순 공통 참조 타입은 C예요.
  • 그렇지 않으면, 두 타입 중 하나는 lvalue 참조 타입 A&이고 다른 하나는 rvalue 참조 타입 B&&이에요 (AB는 cv 한정될 수 있어요). A&B const&의 단순 공통 참조 타입을 D라고 해요. D가 존재하고 std::is_convertible_v<B&&, D>true이면 단순 공통 참조 타입은 D예요.
  • 그렇지 않으면 단순 공통 참조 타입은 없어요.

위에서 사용된 false ? X : Y 형태의 표현식 타입에 대한 정의는 조건부 연산자를 참고하세요.

멤버 타입

멤버 타입 설명
type 모든 T...에 대한 공통 참조 타입

도우미 타입

template < class ... T >
using common_reference_t = std::common_reference<T...>::type;
template < class T, class U, template <class> class TQual, template <class> class UQual >
struct basic_common_reference {};

클래스 템플릿 basic_common_reference는 사용자 정의 타입(주로 프록시 참조)에 대해 common_reference의 결과를 바꿀 수 있게 하는 커스터마이즈 포인트예요. 기본 템플릿은 비어 있어요.

특수화

프로그램은 std::is_same_v<T, std::decay_t<T>>std::is_same_v<U, std::decay_t<U>>가 모두 true이고 T 또는 U 중 적어도 하나가 프로그램 정의 타입에 의존할 때, std::basic_common_reference<T, U, TQual, UQual>의 처음 두 매개변수 TU에 대해 특수화할 수 있어요.

그러한 특수화에 type이라는 멤버가 있다면, 그 멤버는 공개적이고 모호하지 않아야 하며 TQual<T>UQual<U>가 모두 변환될 수 있는 타입을 가리켜야 해요. 또한 std::basic_common_reference<T, U, TQual, UQual>::typestd::basic_common_reference<U, T, UQual, TQual>::type은 같은 타입을 가리켜야 해요.

프로그램은 세 번째나 네 번째 매개변수에 대해 basic_common_reference를 특수화할 수 없고, common_reference 자체도 특수화할 수 없어요. 이러한 규칙을 위반하여 특수화를 추가하면 동작이 정의되지 않아요.

표준 라이브러리는 다음과 같은 basic_common_reference 특수화를 제공해요.

std::basic_common_reference<std::pair> (C++23) pair의 공통 참조 타입을 결정함 (클래스 템플릿 특수화)
std::basic_common_reference<tuple-like> (C++23) 튜플과 튜플 유사 타입의 공통 참조 타입을 결정함 (클래스 템플릿 특수화)
std::basic_common_reference<std::reference_wrapper> (C++23) reference_wrapper와 비-reference_wrapper의 공통 참조 타입을 결정함 (클래스 템플릿 특수화)

참고 사항

기능 테스트 매크로 표준 기능
__cpp_lib_common_reference 202302L (C++23) std::common_reference_t of std::reference_wrapper를 참조 타입으로 만듦

예제

#include <concepts>
#include <type_traits>

static_assert(
    std::same_as<
        int&,
        std::common_reference_t<
            std::add_lvalue_reference_t<int>,
            std::add_lvalue_reference_t<int>&,
            std::add_lvalue_reference_t<int>&&,
            std::add_lvalue_reference_t<int>const,
            std::add_lvalue_reference_t<int>const&
        >
    >
);

int main() {}

같이 보기

common_type (C++11) 타입 그룹의 공통 타입을 결정함 (클래스 템플릿)
common_reference_with (C++20) 두 타입이 공통 참조 타입을 공유함을 지정함 (컨셉)
common_reference (C++26) 반영된 타입 시퀀스의 공통 참조 타입을 결정함 (함수 템플릿)

더 알아보기 (Learn more)

cppreference