Consider this concept, which has a default template parameter.
template<class T, class = decltype([]{})>
concept IsDefined = sizeof(T) > 0;
Since every lambda has a distinct type, one might expect every instantiation of IsDefined<X>
to be distinct.
struct SomeType;
static_assert( false == IsDefined<SomeType> );
struct SomeType
{
// Defined.
};
static_assert( true == IsDefined<SomeType> );
Clang and MSVC agree and compile this code. GCC fails the second static assert, but only if the first static assert is evaluated.
error: static assertion failed
17 | static_assert( true == IsDefined<SomeType> );
Are any of these compilers wrong? Or is this behavior unspecified?
Concepts are not instantiated. Instead, the expression is normalized into a constraint, and then when a concept-id is evaluated, the constraint is checked for satisfaction.
In this case the normal form of IsDefined
is the atomic constraint sizeof(T) > 0
with the identity mapping T -> T
; note that the second parameter does not appear in the mapping (see [temp.constr.atomic]/1). Your code is IFNDR by [temp.constr.atomic]/3:
If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required.