https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117294
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> --- I agree it would be nice, but I'm not sure how to do it. The message *does* say why it fails, but as you point out, the reason it fails is that it's defined in terms of type traits. I think we'd need to special case every std type trait and teach the compiler how to expand it to an explanation of why it evaluates to false. Even if we remove the constrained function template and just write an assertion based on the underlying built-in, there's no more information: struct A { explicit A(int) {} }; template <typename T> struct Foo { T a = 1; }; auto tryit() { static_assert( __is_constructible(Foo<A>) ); } def.cc:11:18: error: static assertion failed 11 | static_assert( __is_constructible(Foo<A>) ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ This is invalid because the "is constructible from zero args" property is false. Why is it false? Well that's a different question! Even if the compiler was taught how to explain why is_constructible_v<T, Args...> is false for any given set of args, presumably you'd only want a more detailed breakdown with -fconcepts-diagnostics-depth increased, or if there's only a single candidate in the overload set. For a bigger overload set, you probably don't want every candidate with unsatisfied constraints to go into great detail, when most of them were not the overload you intended to call anyway. The diagnostic for the unconstrained case would be even better if it said that '1' is not convertible to 'A' because the relevant constructor is 'explicit'.