dimanche 22 janvier 2017

Different compiler behaviors on type trait to test implicit default-constructibility

I've been trying to write a type trait that tells if a type T is implicitly default-constructible. Examples of implicitly/explicitly default-constructible types:

struct Imp { Imp() = default; };
struct Exp { explicit Exp() = default; };

Imp i1{};
Imp i2 = {};  // ok

Exp e1{};
Exp e2 = {};  // error

The type trait I tried looks like this:

#include <type_traits>

template<typename T>
struct IsImplicitlyDefaultConstructible {
private:
  template<typename U> static void helper(const U&);
  template<typename U> static std::true_type test(decltype(helper<U>({}))*);
  template<typename U> static std::false_type test(...);

public:
  static constexpr bool value = decltype(test<T>(0))::value;
};

struct Yes { Yes() = default; };
struct No { explicit No() = default; };

int main()
{
  static_assert(IsImplicitlyDefaultConstructible<Yes>::value, "");
  static_assert(!IsImplicitlyDefaultConstructible<No>::value, "");
}

The idea is to test whether {} is convertible to const T&. Strangely, the code above works on GCC 6.1+, but fails on GCC 4/5 and all versions of Clang. See demo here.

So what is happening? Is this a bug in GCC 6.1+, or in the other versions? How can I make this trait work (preferably with C++11, but okay if C++14 is required)?

Aucun commentaire:

Enregistrer un commentaire