Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is `std::common_type` associative?

The template class std::common_type calculates a common type to a variadic type list. It is defined using the return type of the ternary operator x:y?z recursively. From that definition it is not obvious to me, whether calculating a std::common_type<X,Y> is associative, i. e. whether

using namespace std;
static_assert( is_same<common_type< X, common_type<Y,Z>::type    >::type,
                       common_type<    common_type<X,Y>::type, Z >::type>::value, "" );

will never throw a compile-time error for all types X, Y and Z for which the is_same<...> expression is valid.

Please note, that I'm NOT asking whether

static_assert( is_same<common_type<X,Y>::type,
                       common_type<Y,X>::type>::value, "" );

will ever fire. It will obviously not. The above is a whole different question.

Please note also, that the specification of std::common_type slightly changed in C++14 and will probably change again in C++17. So the answers may be different for different versions of the standard.

like image 371
Ralph Tandetzky Avatar asked Dec 22 '15 10:12

Ralph Tandetzky


2 Answers

This fails on MinGW-w64(gcc 4.9.1). Also fails on VS2013 and (thanks Baum mit Augen) on gcc5.2 or clang 3.7 with libc++.

#include <type_traits>

using namespace std;

struct Z;
struct X{operator Z();};
struct Y{operator X();};
struct Z{operator Y();};

static_assert( is_same<common_type<X,Y>::type,
                       common_type<Y,X>::type>::value, "" ); // PASS

static_assert( is_same<common_type<X,Z>::type,
                       common_type<Z,X>::type>::value, "" ); // PASS

static_assert( is_same<common_type<Y,Z>::type,
                       common_type<Z,Y>::type>::value, "" ); // PASS

static_assert( is_same<common_type< X, common_type<Y,Z>::type    >::type,
                       common_type<    common_type<X,Y>::type, Z >::type>::value, "" ); // FAIL...
like image 135
Cássio Renan Avatar answered Sep 23 '22 09:09

Cássio Renan


#include <type_traits>

struct T2;
struct T1 {
    T1(){}
    T1(int){}
    operator T2();
};
struct T2 {
    operator int() { return 0; }
};
struct T3 {
    operator int() { return 0; }
};
T1::operator T2() { return T2(); }

using namespace std;
using X = T1;
using Y = T2;
using Z = T3;
int main()
{

    true?T2():T3(); // int
    static_assert(std::is_same<std::common_type_t<T2,
                                                  T3>,
                               int>::value,
                  "Not int");

    true?T1():(true?T2():T3()); // T1
    static_assert(std::is_same<std::common_type_t<T1,
                                                  std::common_type_t<T2,
                                                                     T3>>,
                               T1>::value,
                  "Not T1");

    // -----------------------------------------

    true?T1():T2(); // T2
    static_assert(std::is_same<std::common_type_t<T1,
                                                  T2>,
                               T2>::value,
                  "Not T2");

    true?(true?T1():T2()):T3(); // int
    static_assert(std::is_same<std::common_type_t<std::common_type_t<T1,
                                                                     T2>,
                                                  T3>,
                               int>::value,
                  "Not int");

    // -----------------------------------------

    static_assert( is_same<common_type_t< X, common_type_t<Y,Z>    >,
                           common_type_t<    common_type_t<X,Y>, Z > >::value,
                    "Don't match");
}

Ouch! The mental gymnastics here hurt my head, but I came up with a case that fails to compile, printing "Don't match", with gcc 4.9.2 and with "C++14" (gcc 5.1) on ideone. Now whether or not that is conforming is a different matter...

Now the claim is for class types, std::common_type_t<X, Y> should be either X or Y, but I have coerced std::common_type_t<T2, T3> into converting to int.

Please try with other compilers and let me know what happens!

like image 29
BoBTFish Avatar answered Sep 23 '22 09:09

BoBTFish