Why doesn't this overloading/namespace/template-related C++ code compile?

断了今生、忘了曾经 提交于 2019-12-04 18:36:13

问题


Here is some C++ code:

namespace A {

int f(int x) { return 0; }
int f(long x) { return 1; }

template<class T> int g(T x) {
  return f(x);
}

}

namespace B {
struct C {};
}

namespace A {
int f(B::C x) { return 2; }
}

void h() {
  A::g(B::C());
}

In namespace A, the code declares a few overloads of a function f, and a templated function g which calls f. Then we declare a new type in namespace B and overload f for the new type in namespace A. Compiling with g++ 4.2 gives

order.cpp: In function ‘int A::g(T) [with T = B::C]’:
order.cpp:21:   instantiated from here
order.cpp:7: error: no matching function for call to ‘f(B::C&)’
order.cpp:3: note: candidates are: int A::f(int)
order.cpp:4: note:                 int A::f(long int)

The code works if I do any of the following:

  1. Remove the namespaces.
  2. Move the overload of f for B::C into namespace B (thanks to Koenig lookup).
  3. Move the declaration of B::C and its f overload above the definition of g().

I'm particularly puzzled by (3), since I was under the impression that overload resolution should be independent of the order of declarations. Is this expected C++ behavior?


回答1:


Clang gives the following error message, which gives some clues to the problem:

$ clang -fsyntax-only test.cc -Wall
test.cc:7:10: error: call to function 'f' that is neither visible in the
      template definition nor found by argument-dependent lookup
  return f(x);
         ^
test.cc:21:3: note: in instantiation of function template specialization
      'A::g<B::C>' requested here
  A::g(B::C());
  ^
test.cc:17:5: note: 'f' should be declared prior to the call site or in
      namespace 'B'
int f(B::C x) { return 2; }
    ^
1 error generated.

Specifically, you've run into a detail of two-phase lookup of dependent names in template definitions. In C++98, [temp.dep.candidate] says:

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

Since A::f(B::C x) isn't found using associated namespaces (i.e. argument-dependent lookup), it has to be visible at the template definition site, not just at the point of instantiation.




回答2:


For instance

int f(int x) { return 0; }
int f(long x) { return 1; }

functions are not template functions (i.e. they don't have a template <class T> before them. T is a template parameter.) Therefore they can be compiled on the fly when the templated code is reached.



来源:https://stackoverflow.com/questions/8363759/why-doesnt-this-overloading-namespace-template-related-c-code-compile

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