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

Hi,

I recently filed http://llvm.org/bugs/show_bug.cgi?id=21574 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?

Regards
Sebastian

That's not quite what the standard demands;

  T t(args...);

and

  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
handle.

I think that something like:

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

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