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
if T
is valid, otherwise C
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?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…