How can I explicitly refer to an enclosing namespace when an inline namespace exists?

1.3k Views Asked by At

Please consider this code:

#include <iostream>

namespace Foo{

    void ool()  // Version A
    {
        std::cout << "Foo::ool" << std::endl;
    }

    inline namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}


int main()
{
    Foo::ool();  // <- error
}

Both Clang and G++ correctly mark Foo::ool as ambiguous. I can call Foo::Bar::ool without problem but is there a way to call the version A without changing its declaration?

I found people in similar position trying to understand what happens but I did not see a solution for this case.

I am in this situation because I have a project that includes a declaration of std::__1::pair and std::pair, made in different places, with std::__1 being an inline namespace. I need the code to point to the std::pair explicitly. Is there a solution for that?

3

There are 3 best solutions below

1
On BEST ANSWER

I don't think that is possible; from cppreference:

Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.

However, it seems you are not actually in the situation you describe, as you say that the two definitions are pulled from different files. Thus you "bookmark" the more external definition in order to be able to call it when you need it:

#include <iostream>

// Equivalent of first include
namespace Foo{
    void ool()  // Version A
    {
        std::cout << "Foo::ool" << std::endl;
    }
}

const auto& foo_ool = Foo::ool;

// Equivalent of second include
namespace Foo{
    inline namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}

int main()
{
    foo_ool(); // Works
}

If the thing you want to bookmark is a type, a simple using directive should suffice. The equivalent code for you would look like:

#include <my_first_include>

// bookmark code

#include <my_second_include>

// rest of the code
0
On

I don't think you can refer ool ambiguously when an inline namespace do have a method with same name ool .

But You can try this;

#include <iostream>

namespace Foo{

    inline namespace A {
        void ool()  // Version A
        {
            std::cout << "Foo::ool" << std::endl;
        }
    }

    namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}


int main()
{
    Foo::ool();  // no error
}
  1. Wrap methods in namespace Foo in a namespace A then inline namespace A.
  2. Remove inline from Bar.

Now if you make a call Foo::ool(); it will invoke inline A::ool()
Bar::ool can be invoked by Foo::Bar::ool

3
On

You cannot unambiguously refer to the symbol defined in the enclosing namespace once the inline namespace has been seen.

In particular for you case, the qualified lookup in main is rightfully flagged as being ambiguous (as you said yourself). See the last point on cppreference:

Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.


Yet, has other pointed out in comments, you are probably facing a problem of configuration in your toolchain invocation when you try to use std::pair.

To fix you problem, you need to make sure the compiler is invoked to compile C++11 code, which would be with the flag:

-std=c++11 or -std=c++0x depending on your version of Clang/GCC

To give further context:
The inline namespace is a C++11 feature, mainly introduced to allow for symbol versioning in libraries. A C++ standard library implementation could then define different versions of symbols in nested namespaces (with non-standard names), and depending on the requested library version when compiling, the toolchain defines one of those nested namespaces as inline. It seems you are using a c++11 version of the library (since it defines some symbols, in particular pair, in the inline namespace _1), so having symbols in an inline namespace in actually what you want.