Reputation: 611
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?
Upvotes: 25
Views: 1507
Reputation: 9345
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
}
namespace Foo
in a namespace A
then inline
namespace A
.Bar
. Now if you make a call Foo::ool();
it will invoke inline A::ool()
Bar::ool
can be invoked by Foo::Bar::ool
Upvotes: 2
Reputation: 8386
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.
Upvotes: 5
Reputation: 5608
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
Upvotes: 13