views:

78

answers:

2

What part of the C++ specification restricts argument dependent lookup from finding function templates in the set of associated namespaces? In other words, why does the last call in main below fail to compile?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
+13  A: 

This part explains it:

C++ Standard 03 14.8.1.6:

[Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}
Kornel Kisielewicz
+1 Nice answer.
fbrereto
Excellent - thank you.
Huw Giddens
Ah, i couldn't find that reference :) +1
Georg Fritzsche
Yeah, it's a note, so it's not easily findable :/
Kornel Kisielewicz
A: 

Edit: No, this is not right. See @Kornel's answer.


I'm not entirely sure but having consulted Stroustrup's "The C++ programming language" I think that Appendix C section 13.8.4 might be the cause.

Since frob is a template one could conceivably specialise it for i=0 at a point after you call it. This means that the implementation would be left with two possible ways of choosing which frob to call as it appears it can choose it at the point of instantiation or at the end of processing the translation unit.

So, I think the problem is you could do

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}
Troubadour
Nope, take of the namespaces and you still have your problem, don't you? The specialization after usage is a normal problem in C++, the specialized form isn't used if declared after.
Kornel Kisielewicz
@Kornel: Ah yes, that gives a different error, one more in line with what I described. Fair enough, thanks for pointing that out.
Troubadour