Given the types A,B , I am interested in the exact definition of std::common_type<A,B> , not taking into account the variational case of 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 relationships (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 if T valid, otherwise C does not contain a member ::type ("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 the only difference with the built-in arrays and functions, plus cv-qualification, which again don't bother me, so my question is:
Should it be decay<T>::type or just T ? What is the rationale for using decay<T>::type ? It is only a representation of the result A() + B() , for example. for arithmetic expressions?
For example, experimenting a bit, I found that in the case of the definition of "just T " we have
common_type<int&,int&> = int& common_type<int&,long&> = long
that is, the lvalue reference is supported if the types are equal. This reflects the fact that
int a, b; (true ? a : b) = 0;
but
int a; long b; (true ? a : b) = 0;
no. This semantics of “permission of assignment if types are equal” is exactly what I need in a single application, and I tend to believe that common_type and decay should be two independent steps. Should I just use my own definitions?
c ++ conditional-operator c ++ 11 typetraits lvalue
iavr Feb 23 '14 at 22:55 2014-02-23 22:55
source share