Should std :: common_type use std :: decay?

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?

+15
c ++ conditional-operator c ++ 11 typetraits lvalue
Feb 23 '14 at 22:55
source share
1 answer

should std :: common_type use std :: decay?

Yes, see Defect of Library Working Group # 2141 .

Short version (long version, see link above):

  • declval<A>() returns a A&&

  • common_type is specified via 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 therefore gives int&& , which is unexpected

  • proposed 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 gives int

+12
Feb 23 '14 at 23:17
source share



All Articles