依赖模板名称和 C++20 ADL
Dependent template names and C++20 ADL
考虑以下示例:
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);
}
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
Demo.
我有三个相关问题:
- 哪个编译器是正确的,为什么?
- 在 C++17 中,
foo<0>(c)
中的 foo
是否被视为从属名称?
- 在 C++20 中,
foo<0>(c)
中的 foo
是否被视为从属名称?
这是 P0846,这是 C++20 的特性。看来 gcc 还没有实现这个。
这不是依赖名称的问题,而是编译器是否知道 foo
引用模板的问题, foo<
是否进行比较的问题开始做模板参数了。
在 C++17 中,编译器必须已经知道 foo
是一个模板名称(您可以通过添加 using N::foo;
来完成)以便在 C+ 中执行 ADL +20 这不再是真的 - 现在的规则是,如果非限定查找找到一个模板 或者什么都找不到 ,我们也认为它是一个模板。
foo
的依赖性并未因本文而改变。在foo<0>(c);
中,foo
仍然是从属名。 C++17 [temp.dep] 中的规则是:
In an expression of the form:
postfix-expression ( expression-list<sub>opt</sub> )
where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if
- any of the expressions in the expression-list is a pack expansion,
- any of the expressions or braced-init-lists in the expression-list is type-dependent, or
- the unqualified-id is a template-id in which any of the template arguments depends on a template parameter.
第二点适用于此 - c
取决于类型。 C++20 的措辞是相同的。这里的问题不是 foo
不依赖于 C++17。只是规则是当我们foo<
时,我们不知道foo
是一个模板,所以它被认为是小于运算符,并且然后失败。
考虑以下示例:
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);
}
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
Demo.
我有三个相关问题:
- 哪个编译器是正确的,为什么?
- 在 C++17 中,
foo<0>(c)
中的foo
是否被视为从属名称? - 在 C++20 中,
foo<0>(c)
中的foo
是否被视为从属名称?
这是 P0846,这是 C++20 的特性。看来 gcc 还没有实现这个。
这不是依赖名称的问题,而是编译器是否知道 foo
引用模板的问题, foo<
是否进行比较的问题开始做模板参数了。
在 C++17 中,编译器必须已经知道 foo
是一个模板名称(您可以通过添加 using N::foo;
来完成)以便在 C+ 中执行 ADL +20 这不再是真的 - 现在的规则是,如果非限定查找找到一个模板 或者什么都找不到 ,我们也认为它是一个模板。
foo
的依赖性并未因本文而改变。在foo<0>(c);
中,foo
仍然是从属名。 C++17 [temp.dep] 中的规则是:
In an expression of the form:
postfix-expression ( expression-list<sub>opt</sub> )
where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if
- any of the expressions in the expression-list is a pack expansion,
- any of the expressions or braced-init-lists in the expression-list is type-dependent, or
- the unqualified-id is a template-id in which any of the template arguments depends on a template parameter.
第二点适用于此 - c
取决于类型。 C++20 的措辞是相同的。这里的问题不是 foo
不依赖于 C++17。只是规则是当我们foo<
时,我们不知道foo
是一个模板,所以它被认为是小于运算符,并且然后失败。