(Originally separated from this question.)
In the following code snippet,
#include <concepts>
template<
typename T,
typename value_type = typename T::value_type
>
concept check_type = std::default_initializable<T>;
struct Foo {};
template<check_type T>
void func(T t) {}
int main()
{
Foo foo;
func(foo);
}
struct Foo
does not contain the type alias value_type
but it compiles without an error with GCC.
See the result tested on the compiler explorer.
However, with Clang, it reports the following error message:
❯ clang++ -std=c++20 asdf.cpp
asdf.cpp:17:5: error: no matching function for call to 'func'
func(foo);
^~~~
asdf.cpp:12:6: note: candidate template ignored: constraints not satisfied [with T = Foo]
void func(T t) {}
^
asdf.cpp:5:39: note: because substituted constraint expression is ill-formed: no type named 'value_type' in 'Foo'
typename value_type = typename T::value_type
^
1 error generated.
Also see the result tested on the compiler explorer.
Is this a bug?
GCC is correct under the current wording.
Per [temp.deduct]/5, satisfaction checking is done on the associated constraints of the function template:
[temp.constr.decl]/3.2 specifies that the associated constraint is based on the normal form:
Since
check_type
is a concept, it is transparent to normalization ([temp.constr.normal]/1.4), and since the second template parameter ofcheck_type
is not used in its definition, that parameter does not appear in the normal form of the constraint expression. Therefore, the validity (or lack thereof) ofT::value_type
has no effect on satisfaction checking.If you want the concept to check for
value_type
, it is more expressive (not to mention correct) to just check forvalue_type
directly: