嵌套的从属名称不在概念模板中评估

Nested dependent names are not evaluated in template for concept

(最初与分开。)

在下面的代码片段中,

#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 不包含类型别名 value_type 但它使用 GCC 编译时没有错误。

参见result tested on the compiler explorer

但是,对于 Clang,它会报告以下错误消息:

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

另见 result tested on the compiler explorer

这是一个错误吗?

GCC 在当前措辞下是正确的。

根据 [temp.deduct]/5,对函数模板的 关联约束 进行满意度检查:

If the function template has associated constraints ([temp.constr.decl]), those constraints are checked for satisfaction ([temp.constr.constr]).

[temp.constr.decl]/3.2指定关联约束基于范式:

A declaration's associated constraints are defined as follows:

  • ...
  • Otherwise, if there is a single introduced constraint-expression, the associated constraints are the normal form of that expression.

由于check_type是一个概念,它对规范化([temp.constr.normal]/1.4)是透明的,并且由于check_type的第二个模板参数没有在它的定义中使用,所以那个参数确实不会出现在约束表达式的正常形式中。因此,T::value_type 的有效性(或缺乏有效性)对满意度检查没有影响。

如果你想让这个概念检查 value_type,直接检查 value_type 更具有表现力(更不用说正确了):

template <typename T>
concept check_type = std::default_initializable<T> && requires { typename T::value_type; };