Должен ли std:: common_type использовать std:: decay?
Учитывая типы A,B
, меня интересует точное определение std::common_type<A,B>
, не учитывая вариационный случай std::common_type<A...>
для произвольных типов A...
. Итак, пусть
using T = decltype(true ? std::declval<A>() : std::declval<B>());
using C = std::common_type<A,B>;
Теперь, согласно ряду источников, я нашел следующие отношения (для краткости пропуская typename
):
-
cppreference.com: C::type = std::decay<T>::type
-
cplusplus.com: C::type = T
-
GCC 4.8.1 <type_traits>
реализация: C::type = std::decay<T>::type
если T
действительна, в противном случае C
не содержит члена ::type
( "SFINAE-friendly" )
-
Clang 3.3 <type_traits>
реализация: C::type = std::remove_reference<T>::type
Я нахожу "SFINAE-friendly" версию GCC второстепенной деталью, тогда как std::remove_reference
и std::decay
практически отличаются только встроенными массивами и функциями, плюс cv-qualification, для которых опять меня не беспокоят, Поэтому мой вопрос:
Должно ли это быть decay<T>::type
или просто T
? В чем обоснование использования decay<T>::type
? Речь идет только о представлении результата A() + B()
, например. для арифметических выражений?
Например, экспериментируя немного, я обнаружил, что в случае определения "just T
" мы имеем
common_type<int&,int&> = int&
common_type<int&,long&> = long
то есть ссылка lvalue поддерживается, если типы равны. Это отражает тот факт, что
int a, b;
(true ? a : b) = 0;
а
int a;
long b;
(true ? a : b) = 0;
нет. Эта семантика "разрешения присвоения, если типы равны" - это именно то, что мне нужно в одном приложении, и я склонен полагать, что common_type
и decay
должны быть двумя независимыми шагами. Должен ли я просто использовать свои собственные определения?
Ответы
Ответ 1
должен ли std:: common_type использовать std:: decay?
Да, см. Дефект рабочей группы библиотеки # 2141.
Краткая версия (длинная версия, см. ссылку выше):
-
declval<A>()
возвращает a A&&
-
common_type
указан через declval
, n3337:
template <class T, class U>
struct common_type<T, U> {
typedef decltype(true ? declval<T>() : declval<U>()) type;
};
-
common_type<int, int>::type
поэтому дает int&&
, что является неожиданным
-
предлагаемая резолюция заключается в добавлении decay
template <class T, class U>
struct common_type<T, U> {
typedef decay_t < decltype(true ? declval<T>() : declval<U>()) > type;
};
-
common_type<int, int>::type
теперь дает int