Given types A,B
, I am concerned with the exact definition of std::common_type<A,B>
, disregarding the variadic case std::common_type<A...>
for arbitrary types A...
. So let
using T = decltype(true ? std::declval<A>() : std::declval<B>());
using C = std::common_type<A,B>;
Now, according to a number of sources, I have found the following relations (skipping typename
for brevity):
cppreference.com:
C::type = std::decay<T>::type
cplusplus.com:
C::type = T
GCC 4.8.1
<type_traits>
implementation:C::type = std::decay<T>::type
ifT
is valid, otherwiseC
does not contain a::type
member ("SFINAE-friendly")Clang 3.3
<type_traits>
implementation:C::type = std::remove_reference<T>::type
I find the "SFINAE-friendly" version of GCC a minor detail, while std::remove_reference
and std::decay
practically only differ in built-in arrays and functions, plus cv-qualification, for which again I am not concerned much. So my question is
Should it be decay<T>::type
or just T
? What is the rationale of using decay<T>::type
? Is it only about representing result A() + B()
e.g. for arithmetic expressions?
For instance, experimenting a bit, I have found that in the case of the "just T
" definition, we have
common_type<int&,int&> = int&
common_type<int&,long&> = long
that is, an lvalue reference is maintained if types are equal. This reflects the fact that
int a, b;
(true ? a : b) = 0;
is valid, while
int a;
long b;
(true ? a : b) = 0;
is not. This semantics of "allowing assignment if types are equal" is exactly what I need in one application, and I tend to believe that common_type
and decay
should be two independent steps. Should I just use my own definitions?
should std::common_type use std::decay?
Yes, see Library Working Group Defect #2141.
Short version (long version, see link above):
declval<A>()
returns aA&&
common_type
is specified viadeclval
, n3337:template <class T, class U> struct common_type<T, U> { typedef decltype(true ? declval<T>() : declval<U>()) type; };
common_type<int, int>::type
therefore yieldsint&&
, which is unexpectedproposed resolution is to add
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
now yieldsint
来源:https://stackoverflow.com/questions/21975812/should-stdcommon-type-use-stddecay