Search code examples
c++namespacesusing

"using" keyword when defining member functions and non-member functions


Does the "using" keyword have different effects in the context of defining member and non-member functions? The example code below suggests to me that it might.

main.cpp

  #include "baz.h"
  int main()
  {
      foo::bar x;
      x.baz();
      foo::foo_non_member();
  }

baz.h

  namespace foo
  {
      class bar
      {
      public:
          bar() = default;
          void baz();
      };

      void foo_non_member();
  };

baz.cpp

  #include "baz.h"
  #include<iostream>

  using namespace foo;
  void bar::baz()
  {
      std::cout << "baz\n";
  }

  namespace foo
  {
  void foo_non_member()
  {
      std::cout << "non-member\n";
  }
  }

The above code compiles and runs.

$> g++ main.cpp baz.cpp; ./a.out
baz
non-member

If I remove the using namespace foo; from baz.cpp, I get a compiler error.

$> g++ main.cpp baz.cpp
baz.cpp:5:6: error: ‘bar’ has not been declared
 void bar::baz()

If I put that using statement back in and move the definition of foo_non_member() outside of the foo namespace, I get a linker error.

$> g++ main.cpp baz.cpp
/tmp/ccHeSwsZ.o: In function `main':
main.cpp:(.text+0x24): undefined reference to `foo::foo_non_member()'
collect2: error: ld returned 1 exit status

Why does the using keyword appear not to have the same effect here for bar::baz() and foo_non_member()?


Solution

  • For this part:

    using namespace foo;
    void bar::baz()
    {
       std::cout << "baz\n";
    }
    

    The using namespace foo; is used for the lookup of the bar:: part, and due to that the compiler is able to tie the definition of void bar::baz() to the declaration in the namespace foo. And if you remove using namespace foo; it is not able to find bar.

    If I put that using statement back in and move the definition of foo_non_member() outside of the foo namespace, I get a linker error.

    void foo_non_member()
    {
       std::cout << "non-member\n";
    }
    

    Here foo_non_member not have any relation to bar:: or anything else (according to the specs) that would allow the compiler to figure out that this definition is related to the declaration in the namespace foo.

    The standard committee for sure could have added some rules to the specification to allow the compiler to get the foo_non_member definition and the declaration together if the using namespace foo; is present but they decided to don't do so.

    The reason for that is likely because you then would have the ambiguity about whether you want to define a new void foo_non_member() outside of the namespace foo or if you want to have a definition for void foo_non_member() of foo.