Evg*_*Evg 4 c++ templates language-lawyer argument-dependent-lookup c++20
考虑以下示例:
namespace N {
template<class>
struct C { };
template<int, class T>
void foo(C<T>);
}
template<class T>
void bar(N::C<T> c) {
foo<0>(c);
}
int main() {
N::C<void> c;
bar(c);
}
Run Code Online (Sandbox Code Playgroud)
GCC和Clang的失败编译C ++下17个标准(本规范-Werror),因为(根据我的理解)在C ++ 17 ADL不明确时,模板参数不工作<...>存在(除非名称已确定为模板名称),因此foo是未找到的非依赖名称。
在 C++20 中,ADL 规则发生了变化,显式模板参数不会阻止 ADL。现在它似乎foo变成了一个应该可以通过 ADL 解析的依赖名称。但是,GCC 和 Clang 对这段代码的有效性有不同的看法。CLang 编译它没有错误,但 GCC (10.2, -std=c++2a) 抱怨:
error: 'foo' was not declared in this scope; did you mean 'N::foo'?
在 C++17 模式下,Clang 产生以下警告:
warning: use of function template name with no prior declaration in function call with explicit template arguments is a C++20 extension
演示。
我有三个相关的问题:
foo在foo<0>(c)认为是从属名称?foo在foo<0>(c)认为是从属名称?Bar*_*rry 10
这是P0846,它是 C++20 特性。看来 gcc 还没有实现这一点。
这不是依赖名称的问题,而是编译器是否知道foo引用模板的问题,因此是foo<进行比较还是开始进行模板参数。
在 C++17 中,编译器必须已经知道这foo是一个模板名称(你可以通过添加来完成using N::foo;)才能执行 ADL,在 C++20 中这不再是真的 - 现在的规则是如果不合格的查找找到模板或什么都没有,我们也认为它是一个模板。
由于本文, 的依赖性foo没有改变。在foo<0>(c);,foo仍然是一个从属名称。C++17中[temp.dep] 中的规则是:
在以下形式的表达式中:
postfix-expression ( expression-listopt )如果postfix-expression是unqualified-id,则unqualified-id表示依赖名称,如果
- 表达式列表中的任何表达式都是包扩展,
- 表达式列表中的任何表达式或花括号初始化器列表都是类型相关的,或者
- 在不合格-ID是模板id其中任何模板参数取决于模板参数。
第二个要点在这里适用 -c取决于类型。C++20 的措辞是相同的。这里的问题不是foo不依赖于 C++17。只是规则是当 we 时foo<,我们不知道那foo是一个模板,所以它被认为是小于运算符,然后失败了。