Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling function in a namespace without qualification

Looking at the source code of boost::polygon, I have seen many applications of the following theme:

#include <iostream>

namespace B {

struct A {
  void foo() const { std::cout << "foo" << std::endl; }
};

void bar(const A &a) { a.foo(); }
void baz() { std::cout << "baz" << std::endl; }

}

int main(int argc, char **argv) {
  B::A a;
  bar(a);
  B::baz(); // simply calling baz() does not work

  return 0;
}

How is it that bar(a) can be called without extra qualifications? I would have expected that only B::bar(a) would compile.

When the function does not have an argument inside the namespace, this does not occur.

like image 214
vukung Avatar asked Mar 07 '17 13:03

vukung


Video Answer


1 Answers

According to ISO C++14 standard, at §3.4.2:

When the postfix-expression in a function call is an unqualified-id, other namespaces not considered during the usual unqualified lookup may be searched, and in those namespaces, namespace-scope friend function or function template declarations not otherwise visible may be found. These modifications to the search depend on the types of the arguments (and for template template arguments, the namespace of the template argument).

And following:

For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments..

If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the innermost enclosing namespaces of its associated classes.

Actually you can even prevent this from happening by enclosing the function name:

(bar)(a); // doens't compile

while

(B::bar)(a); // does compile

Mind also that this applies only to the innermost namespace, which means that in the following situation you need to qualify the namespace:

namespace B {
   namespace C {
     struct A {};
   }

   void bar(const C::A& a) { ... }
}
like image 86
Jack Avatar answered Nov 04 '22 07:11

Jack