7

This description on cppreference.com says that

The lookup of a dependent name used in a template is postponed until the template arguments are known, at which time [...] ADL examines function declarations with external linkage that are visible from either the template definition context or the template instantiation context.

Contrary to this the following code snippet compiles fine with three compilers (MSVC, clang, gcc):

template <class T>
void CallFoo ()
{
    Foo (T ());
}


class Apple {};


int main ()
{
    CallFoo<Apple> ();
}


static void Foo (Apple)
{
}

Foo is a dependent name in CallFoo: it depends on template argument T. But the function Foo is found by the compiler despite violating two of the above quoted rules.

  • The declaration of Foo is not visible from either the definition or instantiation of CallFoo, because it is below both.
  • Foo has internal linkage.

It is unlikely, that all three compilers have a bug. I might have misunderstood something. Could you elaborate on this?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Dr. Gut
  • 2,053
  • 7
  • 26
  • 1
    I have a similar question with `constexpr` added to it. See [here](https://stackoverflow.com/questions/57501997/adl-does-not-work-in-constexpr-functions-clang-only), – Dr. Gut Aug 26 '19 at 19:07
  • N4713 does not mention "external linkage" regarding argument-dependent name lookup. I think you found a verbiage bug in the cppreference.com site. – Eljay Aug 26 '19 at 19:15
  • 1
    Isn't it ill formed, no diagnostic required? (so all compiler are right :) ) . For implementation, I think they use and of file as instantiation, so they found it. – Jarod42 Aug 26 '19 at 19:33
  • i don't know if some other rule kicks in, but using anonymous namespace (which should also make linkage internal ?) does make it fail, no matter where you put it (after definition of `Apple` of-course). – ustulation Aug 26 '19 at 23:30
  • 2
    @Eljay smells like [CWG1258](http://wg21.link/cwg1258) – Language Lawyer Aug 27 '19 at 00:17
  • The deleted answer by NathanOliver seems to answer the question (for C++17); not sure why it is deleted – M.M Aug 27 '19 at 02:15
  • @M.M: Sorry, I couldn’t see it (via the mobile interface). – Davis Herring Aug 27 '19 at 03:13

1 Answers1

3

In C++03, members of anonymous namespaces could have external linkage despite being unnameable in other translation units. It was therefore thought permissible to preclude actual static functions from dependent ADL. In C++11, anonymous namespaces impose internal linkage, so the restriction became unreasonable. However, despite implementations adopting the new behavior and an issue being filed immediately in 2011 (as noted in the comments), the wording remained in two places until N4810 in March 2019.

As for the placement of the function, this is an artifact of functions having multiple points of instantiation, including the end of any translation unit that instantiates them (with slight adjustments for modules in C++20); if instantiating the function template produces different results for different choices, the program is ill-formed, no diagnostic required (as also noted in the comments).

Dr. Gut
  • 2,053
  • 7
  • 26
Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • "for different choices" -- Did you mean "for different points of instantiation"? Is my example ill-formed? In `CallFoo` `Foo` is not visible. At the end of the file it is. – Dr. Gut Aug 29 '19 at 21:10
  • @Dr.Gut: Yes, that’s what “choices” references here. Yes, that code is ill-formed NDR, because the result of overload resolution depends on the point of instantiation (and because a better match [is available](http://eel.is/c++draft/temp.dep.candidate#1.sentence-3)). – Davis Herring Aug 30 '19 at 00:41