реализация std :: common_type

Чтобы посмотреть, как это работает, я посмотрел на реализацию libstdc ++ std::common_type в шапке type_traits, Я должен признать, что я действительно не понимаю, как это работает. Вот:

/// common_type
template<typename... _Tp>
struct common_type;

template<typename _Tp>
struct common_type<_Tp>
{ typedef _Tp type; };

template<typename _Tp, typename _Up>
struct common_type<_Tp, _Up>
{ typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; };

template<typename _Tp, typename _Up, typename... _Vp>
struct common_type<_Tp, _Up, _Vp...>
{
typedef typename
common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type;
};

Я хорошо понимаю, как работают первая, вторая и четвертая декларации. Однако я не могу понять, как работает третья декларация. Может кто-нибудь попытаться объяснить механизм, используемый здесь?

9

Решение

Прежде всего, std::declval<T>() дает r-значение типа T, Попытка что-либо сделать со значением потерпит неудачу, поэтому его можно использовать только в неоцененном контексте. Далее, троичный оператор определяет его тип как наиболее специализированный тип, общий для обоих аргументов (если такого типа нет, он завершается ошибкой). Итак, тип выражения

true? declval<T0>(): declval<T1>()

является наиболее специализированным распространенным типом T0 а также T1, Осталось только превратить это выражение в тип и убедиться, что оно не оценено. decltype(expr) делает только это Ясно, что версия аргумента с двумя аргументами является логической: другие предназначены для работы с угловым регистром (один аргумент) и для использования версии с двумя аргументами для получения общего типа произвольных типов.

10

Другие решения

Третья версия использует условный оператор определить общий тип. Его правила довольно подробно описаны в разделе 5.16 стандарта, поэтому я не уверен, что мне следует их здесь скопировать.

Проще говоря, выражение:

boolean-expression ? second-operand : third-operand

имеет «общий тип» второго и третьего операндов, если таковые существуют. decltype Затем спецификатор используется для «преобразования» выражения в спецификатор типа.

3

Long Story Short: decltype заставляет компилятор C ++ определять тип ближайшего предка для него.

Третичные операторы имеют результирующий статический тип ближайшего предка из двух возможных выражений.

Например:

А наследует от Б

Х наследует от Y наследует от B

<expression> ? <expression with static type A> : <expression with static type X>
= <expression with static type B>  // this is how the C++ parser sees it

Вот как работает язык C ++. Decltype просто делает typedef статическим типом результата этого выражения (каким бы типом его не определял компилятор C ++)

1