David Doria
David Doria

Reputation: 10273

Namespace search order

I have two namespaces that each have a function with the same name. If from one of the namespaces I want to call the function that matches the best. From a function in NamespaceA, if I call MyFunction(...), of course it uses the one in NamespaceA. However, if I add a 'using NamespaceB::MyFunction', I would then expect the behavior I described. However, what I actually see is that it ALWAYS finds the NamespaceB function, even though I am in NamespaceA. HOWEVER, if I ALSO add a using::NamespaceA (even though I am already in NamespaceA), it works as I'd expect. A demonstration is below. Can anyone explain how this works?

#include <iostream>

namespace NamespaceA
{
  void DoSomething();
  void MyFunction(int object);
}

namespace NamespaceB
{
  void MyFunction(float object);
}

namespace NamespaceA
{
  void DoSomething()
  {
    using NamespaceA::MyFunction; // Note that without this line the lookup always fins the NamespaceB::MyFunction!
    using NamespaceB::MyFunction;

    MyFunction(1);
    MyFunction(2.0f);
  }

  void MyFunction(int object)
  {
    std::cout << "int: " << object << std::endl;
  }
}

namespace NamespaceB
{
  void MyFunction(float object)
  {
    std::cout << "float: " << object << std::endl;
  }
}

int main(int argc, char *argv[])
{
  NamespaceA::DoSomething();

  return 0;
}

Upvotes: 7

Views: 3924

Answers (3)

Konstantin Burlachenko
Konstantin Burlachenko

Reputation: 5685

Short answer: Local defined name and the name declared by a using-declaration hides nonlocal names.

Detailed answer:

Your question is very interesting. I didn't open standarts of C++98,03,11 for that question, but open Bjarne Stroustrup's book

Namespace - is a named scope. Verbosity can be eliminated using two techniques:

  • create synonymous with using NS :: x; (using-declaration)
  • create synonymous for all the variables with using namespace NS :: x; (using-directive)

The answer to your question is here:

Appendix B 10.1
local definitions, and names defined with using-declaration hides 
the name of a non-local definitions.

Bonus with opposite situation:

Also if you

using NamespaceA::MyFunction;
using NamespaceB::MyFunction;

change to

using namespace NamespaceB;

Then you due to text below get situation with call only void MyFunction(int object)

8.2.8.2
Names explicitly declared in namespace (also made with using declaration)
have priority over the names made available by using directives

Extra code to play with:

#include <iostream>

// var in global namespace
const char* one = "G_one";

// vars in named namespace
namespace NS1 {
    const char* one = "NS1_one";
    const char* two = "NS1_two";
    const char* three = "NS1_three";
}

namespace NS2 {
    const char* one = "NS2_one";
    const char* two = "NS2_two";
    const char* three = "NS2_three";
}

int main(int argc, char *argv[])
{

    using namespace NS1;       // using-directive
    using namespace NS2;       // using-directive

    // const char* two = "L_two"; // local namespace
    using NS2::two;               // using-declaration

    // C++ rules
    // Local names and names with using-declarations
    // takes precedence over the name of the NS     
    std::cout << "two: " << two << std::endl;

    //std::cout << "three: " << three << std::endl; // ambiguous symbol

    // But the name in global-namespace does not have priority over imported name from namespace
    //std::cout << "one: " << one << std::endl; // ambiguous symbol. Because wGlobal names does not have priority over
    return 0;
}

Upvotes: 0

chisophugis
chisophugis

Reputation: 799

It has to do with the order in which different parts of the program are looked in to find a name. For the situation you mention, it has to do with the scope of the function's top-level block being searched for before the enclosing namespace. Basically, the using declaration brings that name into the top-level scope of DoSomething, and since that scope is looked in before the enclosing namespace scope, then if a matching function is found there, then the enclosing namespace scope isn't considered.

I have glossed over a lot of stuff that isn't relevant in your example (for example, if the argument were not a built-in type then, believe it or not, names from the scope where that type was defined could be considered as well. For the whole story, see section 3.4 here. It's pretty scary, about 13 pages to describe all this stuff; but don't bother with it unless you really are curious, because most of the stuff is there so that it "works the way you expect", more-or-less. That document is not the real Standard but actually a working draft with some corrections, so it is basically the real C++ Standard plus some bugfixes.

Upvotes: 2

Mike Corcoran
Mike Corcoran

Reputation: 14565

i believe namespaces use the same scoping rules as variables. so if you have a local namespace, lookups will happen there first before moving to the outer scope.

i'm not sure what the rules are for the situation where you have imported two namespaces with the same function names, but you should always fully qualify the function calls in that scenario just for clarity, instead of relying on some nuance of the language implementation for namespaces that people may not be familiar with.

Upvotes: 0

Related Questions