Чтобы посмотреть, как это работает, я посмотрел на реализацию 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;
};
Я хорошо понимаю, как работают первая, вторая и четвертая декларации. Однако я не могу понять, как работает третья декларация. Может кто-нибудь попытаться объяснить механизм, используемый здесь?
Прежде всего, std::declval<T>()
дает r-значение типа T
, Попытка что-либо сделать со значением потерпит неудачу, поэтому его можно использовать только в неоцененном контексте. Далее, троичный оператор определяет его тип как наиболее специализированный тип, общий для обоих аргументов (если такого типа нет, он завершается ошибкой). Итак, тип выражения
true? declval<T0>(): declval<T1>()
является наиболее специализированным распространенным типом T0
а также T1
, Осталось только превратить это выражение в тип и убедиться, что оно не оценено. decltype(expr)
делает только это Ясно, что версия аргумента с двумя аргументами является логической: другие предназначены для работы с угловым регистром (один аргумент) и для использования версии с двумя аргументами для получения общего типа произвольных типов.
Третья версия использует условный оператор определить общий тип. Его правила довольно подробно описаны в разделе 5.16 стандарта, поэтому я не уверен, что мне следует их здесь скопировать.
Проще говоря, выражение:
boolean-expression ? second-operand : third-operand
имеет «общий тип» второго и третьего операндов, если таковые существуют. decltype
Затем спецификатор используется для «преобразования» выражения в спецификатор типа.
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 ++)