libcxx: std::is_constructible only allows implicit conversion for scalar and reference types. Bug?


I recently filed because I think the library implementation of std::is_constructible is broken.

For a type

struct S {
     template <typename T> explicit operator T() const;
     explicit operator int const&() const;

both std::is_constructible< int, S > and std::is_constructible< int const&, S > report false despite the explicit cast operators and although

T t;
int const& i1(t);
int i2(t);

compile fine.

What was the rationale for specializing std::is_constructible for scalar and reference types at all? Without this entire special-cased branch, std::is_constructible<S, Args...> simply forwards to the SFINAE expression decltype(std::move(S(std::declval<Args>()...))). Isn't that what should always be evaluated because it tests that S(Args...) is a valid expression, just like the standard demands?

Am I missing something?


That's not quite what the standard demands;

  T t(args...);



are not valid in the same set of circumstances. In particular, they can
differ when args contains exactly one expression (or zero). T(arg) is
equivalent to (T)arg, which can perform a superset of the conversions
performed by T t(arg), and I would imagine this is what libc++ is trying to

I think that something like:

  decltype(::new S(std::declval<Args>()...))

... would cover all cases other than when S is a reference type.