Consider the following example:
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);
}
Both GCC and Clang fail to compile this code under C++17 standard (with -Werror
), because (according to my understanding) in C++17 ADL doesn't work when explicit template arguments <...>
are present (unless a name is already established as a template name), so foo
is a non-dependent name that is not found.
In C++20, the ADL rules have changes, and explicit template arguments don't prevent ADL. Now it seems that foo
becomes a dependent name that should be resolvable via ADL. However, GCC and Clang have different opinions about the validity of this code. CLang compiles it without errors, but GCC (10.2, -std=c++2a
) complains:
error: 'foo' was not declared in this scope; did you mean 'N::foo'?
In C++17 mode, Clang produces the following warning:
warning: use of function template name with no prior declaration in function call with explicit template arguments is a C++20 extension
Demo.
I have three related questions:
foo
in foo<0>(c)
considered as a dependent name?foo
in foo<0>(c)
considered as a dependent name?This is P0846, which is a C++20 feature. It appears that gcc does not implement this yet.
It's not a question of dependent name or not, it's a question of does the compiler know that foo
refers to a template or not, and so is foo<
doing a comparison or is it starting to do template parameters.
In C++17, the compiler had to already know that foo
was a template-name (which you could accomplish by adding using N::foo;
) in order to perform ADL, in C++20 that's no longer true - now the rule is that if unqualified lookup finds a template or nothing, we also consider it to be a template.
The dependence of foo
didn't change as a result of this paper. In foo<0>(c);
, foo
is still a dependent name. The rule in [temp.dep] from C++17 was:
In an expression of the form:
postfix-expression ( expression-listopt )
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.
The second bullet applies here - c
is type-dependent. The C++20 wording is the same. The issue here wasn't that foo
wasn't dependent in C++17. It's just that the rule was when we foo<
, we don't know that foo
is a template, so it's considered the less-than-operator, and that then fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With