GCC, Clang, and IBM disagree on how to perform template-parameter-dependent name lookup. Which one is right?

亡梦爱人 提交于 2019-12-20 11:22:30

问题


Consider this example I found on IBM's website:

#include <iostream>
using namespace std;

void f(double) { cout << "Function f(double)" << endl; }

template<class T> void g(T a) {
  f(123);
  h(a);
}

void f(int) { cout << "Function f(int)" << endl; }
void h(double) { cout << "Function h(double)" << endl; }

void i() {
  extern void h(int);
  g<int>(234);
}

void h(int) { cout << "Function h(int)" << endl; }

int main(void) {
    i();
}

What will it print?

  • The IBM documentation I adapted this example from, available here, says it will print:

    Function f(double)
    Function h(double)
    

    The rationale for this is that template-parameter-dependent name lookup is performed right before the instantiation of i(), so it finds h(double) but not h(int).

  • When I compile it using GCC 4.4.1, it prints:

    Function f(double)
    Function h(int)
    

    GCC seems to be looking up the template-parameter-dependent names in the template after everything else has been compiled, so it finds both h(double) and h(int), and prefers the latter.

  • When I compile it using Clang 2.8, it fails to compile. The compiler error is:

    ibm_example.cc:8:3: error: use of undeclared identifier 'h'
      h(a);
      ^
    ibm_example.cc:16:3: note: in instantiation of function template specialization 'g<int>' requested here
      g<int>(234);
      ^
    1 error generated.
    

    Clang seems to be looking up the template-parameter-dependent names in the template at the point where the template is declared, so it finds neither h(double) nor h(int).

Which one is right?


回答1:


They are all correct. No really, read on...

template<class T> void g(T a) {
  f(123);
  h(a);
}

Here, f is a non-dependent name but h is a dependent name according to 14.6.2/1. f is looked up

Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used.

f is looked up immediately and bound to void f(double), the only f visible at that point.

According to 14.6.4.1 the point of instantiation of void g<int>(int) is immediately after the definition of void i(), where it is used.

[..]Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

This means that sources for resolving the dependent name are declarations visible at the definition of template<class T> void g(T a) and "declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context" (14.6.4).

However, because int is a fundemantal type, the set of associated namespaces is empty (3.4.2) (no, not even the global namespace is included) and according to 14.6.4.2 it is only lookup using the associated namespaces that can use the template instantiation context, normal unqualified name lookup can only use what is visible at the template definition context. This confirms what was said in 14.6.4.

Now, the bonus point. 14.6.4.2 goes on to say:

If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.

The call is ill formed because lookup fails (the part about associated namespaces doesn't apply here), so the behavior is explicitly undefined so anything could happen. Hence none of the behaviours seen shows a non-conformance with the standard although, to me, Clang's diagnostic seem most in keeping with the standard.

(All references ISO/IEC 14882:2011.)



来源:https://stackoverflow.com/questions/7369314/gcc-clang-and-ibm-disagree-on-how-to-perform-template-parameter-dependent-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!