简体   繁体   中英

Dependent template names and C++20 ADL

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:

  1. Which compiler is right and why?
  2. In C++17, is foo in foo<0>(c) considered as a dependent name?
  3. In C++20, is 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-list opt )

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM