Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::common_type with references to type_info

Tags:

I'm perplexed: upon upgrading to GCC 6 (RC1) some template code using std::common_type that worked before failed. I tried on clang, and that also fails...so I must be doing something wrong!

The code amounts to:

#include <type_traits>
#include <typeinfo>

using namespace std;

// common_type of two const type_info& is ok (compiles ok)
common_type<const type_info&, const type_info&>::type func1();

// common_type of three type_info& is bad...(fails to compile)
common_type<const type_info&, const type_info&, const type_info&>::type func2();

// common_type of two const int& is ok
common_type<const int&, const int&>::type func3();

// common_type of three const int& is ok too!
common_type<const int&, const int&, const int&>::type func4();

The second common_type with three parameters of type std::type_info const & fails to compile. clang cryptically suggests I use a two-argument std::common_type, but this is in a template expansion where I can't control the inputs!

This seems very odd: why would the const type_info& case with 3 fail but not any of the other seemingly-equivalent type fail?

See here: https://godbolt.org/g/Ob4y0x

like image 814
Matt Godbolt Avatar asked Apr 18 '16 21:04

Matt Godbolt


1 Answers

First, common_type_t<T1, T2> is (roughly) std::decay_t<decltype(true? std::declval<T1>() : std::declval<T2>())>. It decays the type - strip away referenceness, remove top-level cv-qualification, and does the array-to-pointer and function-to-pointer conversion.

So, common_type<const type_info&, const type_info&>::type is type_info. While func1's declaration appears to work, you'll have serious problems writing its definition.

common_type_t<T1, T2, T3> is common_type_t<common_type_t<T1, T2>, T3>, so common_type<const type_info&, const type_info&, const type_info&>::type is common_type<type_info, const type_info&>::type.

That results in a mixed-value-category ternary expression, which by the rules in [expr.cond] will try to make a temporary type_info out of the chosen operand - which doesn't work because type_info's copy constructor is deleted.

In SFINAE-friendly implementations, that results in common_type<const type_info&, const type_info&, const type_info&> having no member type. If you use a non-SFINAE-friendly implementation, you'll get a hard error instead.

like image 132
T.C. Avatar answered Sep 17 '22 09:09

T.C.