I found a problem concerning namespace search.
The following simplified code failed to compile:
namespace A {
namespace B {
class Test {
};
}
namespace C {
namespace B {
typedef B::Test AnAlias;
}
}
}
The compiler complains that Test in namespace A::C::B does not name a type.
The problem seems to be that the compiler sees a namespace B inside namespace C and does not no further search. I would have exspected that he also would look in namespace A (which is a enclosing namespace) and find the B::Test there.
If I rename C::B everything is fine.
If I qualify A::B::Test everything is fine.
If I put the typedef directly in namespace A::C everything is fine.
This behavior was tested with gcc 4.1 and intel 12 compiler. (both for linux).
Are the compilers right?
The B in typdef B::Test resolves to A::C::B. If you're going to reuse the name B, you need to specify it to remove the ambiguity. The compilers are behaving properly. IIRC, names are resolved to the closest declaration to its use or reference. In this case A::C::B is the closest declaration to the typedef.
Related
I have some C++ libraries that are written using nested namespaces. These libraries use many mathematical functions that, for readability, are better off read without explicitly specifying namespaces. Right now, a simplified version of the code would look like this.
namespace Base::Sibling1 {
float cos(float x) { return cosf(x); }
};
namespace Base::Sibling2 {
using namespace Sibling1;
float f(float x) { return cos(x); }
};
We wanted to move to use flatter namespaces mostly to make it easier to extend the library with sibling code. We had hoped that a simple change like this would work:
namespace Sibling1 {
float cos(float x) { return cosf(x); }
};
namespace Sibling2 {
using namespace Sibling1;
float f(float x) { return cos(x); }
};
Instead this fails now since Sibling2::f() calls cos(x) that is now ambiguous.
I have two questions
why is it ambiguous now and not int the first version?
is it possible to obtain the behavior we had before without listing all functions explicitly using using Sibling1::cos?
The ambiguity is due to how using directives work.
[namespace.udir] (emphasis mine)
2 A using-directive specifies that the names in the nominated
namespace can be used in the scope in which the using-directive
appears after the using-directive. During unqualified name lookup
([basic.lookup.unqual]), the names appear as if they were declared in
the nearest enclosing namespace which contains both the
using-directive and the nominated namespace. [ Note: In this context,
“contains” means “contains directly or indirectly”. — end note ]
3 A using-directive does not add any members to the declarative
region in which it appears. [ Example:
namespace A {
int i;
namespace B {
namespace C {
int i;
}
using namespace A::B::C;
void f1() {
i = 5; // OK, C::i visible in B and hides A::i
}
}
namespace D {
using namespace B;
using namespace C;
void f2() {
i = 5; // ambiguous, B::C::i or A::i?
}
}
void f3() {
i = 5; // uses A::i
}
}
void f4() {
i = 5; // error: neither i is visible
}
— end example ]
So given your structure of namespaces, according to bit I made bold in paragraph 2, when you write
using namespace Sibling1;
It kinda translates to this
namespace /* Enclosing */ {
using Sibling1::cos;
namespace Sibling2 {
float f(float x) { return cos(x); }
};
}
The namespace I marked as enclosing is either Base or the global namespace. The "kinda" bit (according to paragraph 3) is that it's not an actual declaration being added. I.e. if something named cos already exists in /* Enclosing */, it's not a re-declaration. This is by design, because using directives can potentially bring a lot of names in, and so it shouldn't cause an error when the names they bring are not actually used.
In your case however, the name brought in is used.
When /* Enclosing */ is Base, it matches only one declaration, the one in Sibling1, as-if it was declared in Base.
When /* Enclosing */ is the global namespace, it matches the actual declaration there too, presumably the one brought in by math.h (you seem to be using that). So you get an ambiguity (the name refers to two potential entities).
So on the whole, compilers that reject this code are behaving as expected. While I understand your plight, I don't think there's really a problem for you to solve here. If client code finds Base::Sibling1::cos too verbose, it itself can employ a using directive of the form using namespace Base;. Or using a namespace alias to shorten things namespace sib1 = Base::Sibling1;.
The problem cannot be reproduced as you describe it. Moreover, there is no reason that the flattening alone introduces ambiguities, if you use expose in the siblings the same names you introduced in Base. So, the root cause is probably in some parts of the code you are not showing.
The second version does not define cosf(), so you probably are using some namespace. If in that namespae there is also a cos() you create an ambiguity between the two overloads. I could reproduce this by using namespace std:
#include <iostream>
#include <cmath>
using namespace std;
namespace Sibling1 {
float cos(float x) { return cosf(x); }
}
namespace Sibling2 {
using namespace Sibling1;
float f(float x) { return cos(x); }
}
Online demo: the compilation error indicates which are the candidates behind the ambiguity. If you now comment the using namespace out, the ambiguity goes away, and the code compiles. Online proof.
Namespaces are meant to avoid naming conflicts and keep control of ambiguities:
Creating a namespace and systematically using namespace everywhere defeats the whole purpose.
On the other side, long using lists are painful to maintain, especially if you have to repeat them in several sibling namespaces. This is probably why the Base and the nesting were created in the first place.
In the first version, you do not show what's in Base. It is possible that some more tailored using clauses are used therein instead of full namespaces: if selectively injecting the really required functions in the Base namespace, they are made available within the siblings avoiding ambiguity that can be introduced by injecting the name of unnecessary functions.
A project I'm working on requires multiple targets to be compiled for. Per target the underlying implementation may vary as the device requires hardware to be configured differently.
In order to force target implementations to follow a interface/design contract system was designed. If a target does not implement said interface accordingly, an error will be thrown upon usage.
The following code is tested using gcc, arm-none-eabi-gcc and clang
namespace A {
namespace C {
void foo() {}
}
}
namespace B {
using namespace A::C;
void foo() {}
}
using namespace A;
namespace C {
}
int main() {
B::foo(); // ok
C::foo(); // won't compile
return 0;
}
Now there are multiple questions that arise when reasoning why this code would compile or not:
Why does the compiler not report unresolved ambiguity between A::foo(bool) and B::set(bool)?
Why does C::foo() not compile, since my theory is that the same naming structure is achieved but on a different manner:
Why does the compiler not report unresolved ambiguity between target::set(bool) and interface_contracts::set(bool)?
In the first code snippet, name hwstl::target::pin::set hides name hwstl::interface_contracts::pin::set.
For the call hwstl::device::pin::set(true);, name lookup stops upon finding hwstl::target::pin::set. Only one candidate function, no ambiguity.
For the call hwstl::unsatisfied_device::pin::set(true);, there is only one function called set which can be found anyway.
10.3.4.1 A using-directive does not add any members to the declarative region in which it appears.
Why does the following code not compile?
In the second code snippet, you call set by qualified id: hwstl::unsatisfied_device::pin::set, compiler will only try to find name inside namespace hwstl::unsatisfied_device::pin. Thus it failed in finding the name introduced by the using directive using namespace interface_contracts; outside it.
Here is a simplified version of your code:
namespace A {
void foo() {}
}
namespace B {
using namespace A;
void foo() {}
}
using namespace A;
namespace C {
}
int main() {
B::foo(); // ok
C::foo(); // won't compile
return 0;
}
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?
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
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.
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
}
Wrap methods in namespace Foo in a namespace A then inline namespace A.
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
Suppose I have the following defined in a header file:
namespace MyNamespace
{
Class global_c;
}
Then I do this in a source file:
namespace MyNamespace
{
void MyClass::Function( )
{
::global_c.DoSomething( );
}
}
global_c turns out as undefined by the compiler, if I do just global_c.DoSomething( ); however it compiles fine, if I add 'using namespace MyNamespace;' to the top of the file it also works fine.
Since global_c lives in the same namespace as 'MyClass' why can't it be resolved just because '::' is added to the front of it?
Because you are explicitly telling the compiler to use the global namespace by prepending the variable with ::. As global_c does not exist in the global namespace it throws an error.
The compiler is just doing what you told it to do. Think of :: as Global::.
Could somebody tell me what is the difference between
using namespace android;
....
and
namespace android {
....
}
I found that almost all .cpp files in Android source code use the second one.
Also, If I want to include some files that use the type of second one in my own project, do I need to use namespace android{...} too?
Because if I do not, compiler would report error when I call methods of included files. Or do I need to add any prefix before method call?
namespace android {
extern int i; // declare here but define somewhere
void foo ();
}
-- is used for scoping variables and functions inside a particular name. While using/calling those variables/functions, use scope resolution operator ::. e.g.
int main ()
{
android::foo();
}
There is no restriction for putting all namespace declarations in a single body instance. Multiple namespace android bodies spread across several files, is possible and also recommended sometimes. e.g.
// x.cpp
namespace android {
void somefunc_1 ();
}
// y.cpp
namespace android {
void somefunc_2 ();
}
Now, sometimes you may find using :: operator inconvenient if used frequently, which makes the names unnecessarily longer. At that time using namespace directive can be used.
This using directive can be used in function scope / namespace scope / global scope; But not allowed in class scope: Why "using namespace X;" is not allowed inside class/struct level?).
int main ()
{
using namespace android;
foo(); // ok
}
void bar ()
{
foo(); // error! 'foo' is not visible; must access as 'android::foo()'
}
BTW, Had using namespace android; declared globally (i.e. above main()), then foo() can be accessed without :: in Bar() also.
My answer is probably only helpful if you are more experienced with Java. I'm guessing since you are doing android stuff that this is the case.
The following means that you are declaring a class called MyClass in the namespace android. The qualified name of the class would be android::MyClass.
namespace android {
class MyClass {...};
}
It can be thought of similarly to the Java code:
package android;
public class MyClass {...}
The following means that you can use classes, functions etc. defined in the android namespace without having to use their qualified name (assuming they have been included).
using namespace android;
This
#include <path/to/MyClass.h>
using namespace android;
can be thought of similarly to the Java code:
import android.MyClass;