Is it legal to replace something like this:
namespace foo {
namespace bar {
baz();
}
}
with something like this:
namespace foo::bar {
baz();
}
?
You can combine namespaces into one name and use the new name (i.e. Foobar).
namespace Foo { namespace Bar {
void some_func() {
printf("Hello World.");
}
}}
namespace Foobar = Foo::Bar;
int main()
{
Foobar::some_func();
}
Pre C++17:
No, it's not. Instead of a bunch of indented nested namespaces, it's certainly valid to put them on the same line:
namespace Foo { namespace Bar { namespace YetAnother {
// do something fancy
} } } // end Foo::Bar::YetAnother namespace
C++17 Update:
You can now nest namespaces more cleanly in C++17:
namespace Foo::Bar::YetAnother {
// do something even fancier!
}
For anyone wondering, the form namespace foo::bar is supported since C++17. References:
http://en.cppreference.com/w/cpp/language/namespace
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.html
Qualified names, like something::someting_else in C++ can only be used to refer to entities that have already been declared before. You cannot use such names to introduce something previously unknown. Even if the nested namespace was already declared before, extending that namespace is also considered as "introducing something new", so the qualified name is not allowed.
You can use such names for defining functions previously declared in the namespace
namespace foo {
namespace bar {
int baz();
}
}
// Define
int foo::bar::baz() {
/* ... */
}
but not declaring new namespaces of extending existing ones.
No; it's a syntax error.
Did you try it? Visual C++ gives me the following errors:
1>C:\...\foo.cpp(31): error C2061: syntax error : identifier 'bar'
1>C:\...\fooo.cpp(31): error C2143: syntax error : missing ';' before '{'
As per the grammar in $2.10, an identifier cannot have the token ":". So the name foo::bar is ill-formed.
Related
Is this standard in C++? In C#, I liked declaring nested namespaces like this:
namespace A.B
{
class X
{
};
}
The alternative was this, which is a little uglier:
namespace A
{
namespace B
{
class X
{
};
}
}
In C++, I wanted to see if it had a similar feature. I ended up finding this works:
namespace A::B
{
class Vector2D
{
}
}
Notice the ::.
I'm curious if this is standard C++ or if this is a MS feature. I can't find any documentation on it. My ancient C++98 reference book doesn't mention it, so I wonder if it's an extension from Microsoft or a new feature.
Yes, this is legal C++ 17 syntax. It is, however, not called embedded namespace, but nested namespace.
namespace ns_name::name (8) (since C++17)
[...]
8) nested namespace definition: namespace A::B::C { ... } is equivalent to namespace A { namespace B { namespace C { ... } } }.
See the code below:
#include <iostream>
/// Definition of void perform(a_lib::a_class&). Where should I put this definition?
/// See the comments below for where I've tried placing it.
// void perform(a_lib::a_class&) {
// std::cout << "performing on a_lib::a_class" << std::endl;
// }
namespace a_lib {
class a_class { };
// WORKS HERE but it pollutes a_lib (namespace of third-party library).
}
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
}
// WORKS HERE but it pollutes the global namespace.
namespace b_lib {
// WORKS HERE but it pollutes b_lib (namespace of third-party library).
template <typename Type>
void b_func(Type& obj) {
perform(obj);
}
}
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
void run() {
a_lib::a_class a_obj;
b_lib::b_func(a_obj);
}
}
int main(int, char**) {
mine::run();
return 0;
}
a_lib and b_lib are namespaces belonging to two different third-party libraries. mine is my own namespace.
I've been taught that it's a bad idea to pollute the global namespace and in this question they also say that adding types to std is a bad idea. I'm thinking the latter is true for namespaces in general; you should not add types to a namespace that's not yours.
But how I would I solve the problem above without breaking these principles? Where should I put the definition of perform() and how can I get b_func() to call it?
Context: I'm trying to add an external cereal serialize() for a SFML type in my own namespace. This here is a reduced example.
You need to identify where the compiler, when processing "b_func" can find the "perform".
namespace mine {
// DOESN'T WORK HERE: "use of undeclared identifier 'perform'".
// dom - yes it will, but there is 'more' to the name than your example shows
void perform(Type& obj) { /* do something with obj */}
}
// WORKS HERE but it pollutes the global namespace.
namespace b_lib {
// WORKS HERE but it pollutes b_lib (namespace of third-party library).
// dom - use here is easy with correct and 'more-complete' name:
template <typename Type>
void b_func(Type& obj) { mine::perform(obj); }
// -----------------------^^^^^^^^^^^^^^^^^^^ --- more to name
}
Since "mine" is a namespace, a more complete name can 'reach across' the name spaces.
Note that at mine::perform() implementation, "Type" must also be defined to use the obj.
I have declared a class Integer in a custom namespace:
namespace MyNameSpace
{
class Integer {};
}
And I am using it in a method like this:
void someMethod()
{
using namespace MyNameSpace;
SomeClass x(Integer("some text", 4));
}
This gives
10> error C2872: 'Integer' : ambiguous symbol
10> could be 'g:\lib\boost\boost_1_47_0\boost/concept_check.hpp(66) : boost::Integer'
10> or '[my file] : MyNameSpace::Integer'
I have searched my code base for "namespace boost" and "using boost" with fulltext search but didn't find a line like "using namespace boost;". This is supported by the test that
void someMethod()
{
shared_ptr<int> x;
using namespace MyNameSpace;
//SomeClass x(Integer("some text", 4));
}
gives
error C2065: 'shared_ptr' : undeclared identifier
whereas
void someMethod()
{
boost::shared_ptr<int> x;
using namespace MyNameSpace;
//SomeClass x(Integer("some text", 4));
}
compiles.
Is there any other reason why the "ambiguous symbol" error can occur??
Compiler just prevents you from mixing this classes up. Even when you are not using namespace "boost".
Namespaces are essentially "last names" or "family names" for the stuff in them. In your case Integer()'s whole name is MyNameSpace::Integer(). You specific errors are a splendid example of the first rule of using namespaces. DO NOT USE "USING" STATEMENTS! If you leave them out completely, yes, you have to type a few extra things to placate the compiler. But you never have collisions or to ask anything like "does boost have an Integer somewhere".
Secondly, someMethod() is outside any class and outside any namespace. It really ought to look more like MyNameSpace::Integer::someMethod() or more reasonably be inside a
namespace MyNameSpace
{
Integer::someMethod(
}
Once you do this, the compiler WILL help you find where stuff is or isn't.
Good luck!
I'm learning C++ now. What are the complete legal entities that can be put in a namespace?
Legal entities here means valid members of a namespace
Oh, this is a real question. I'm coming from .net and I have the .net mindset.
Any code can be put inside namespace.
However main() function must be at global namespace. It cannot be put inside user-defined namespace.
namespace userns
{
int main()
{
return 0;
}
}
This program wouldn't compile link : http://www.ideone.com/k6SPc
Its because userns::main() will not be considered entry-point of the program; it became just like any other user function, not the standard main(). To compile it successfull, you've to add main() at global namespace:
namespace userns
{
int main()
{
return 0;
}
}
int main()
{
return 0;
}
This will compile link now : http://www.ideone.com/76Ynu
Anything can be put in a namespace (which is legal for C++, of course).
Actually, everything is in some namespace - the global namespace, if not specified.
Everything can be put in namespace except few "entities", which will not compile.
(1) Globally overloaded operator new and operator delete
namespace N
{
void* operator new (size_t size) // error
{ ... }
}
(2) Definition of the constructs which are declared in outer scope of the namespace; for example you have a class A declared globally then you cannot define its method inside your namespace N. In the same way, if you have method declared in a namespace N then you cannot put its definition inside namespace N::Nested (i.e. Nested is a namespace inside N).
//file
struct A {
void foo ();
static int i;
};
namespace N
{
int A::i = 0; // error
void A::foo() // error
{}
}
Demo: this is not allowed.
I remember at least these 2 restrictions from my experience. Don't know about specs.
I expected to be able to use a namespace alias in a class declaration but get a compiler syntax error.
struct MyClass
{
namespace abc = a_big_namespace;
void fn() {
abc::test();
}
};
The only way I can get it to work is to put the alias in every function.
void fn() {
namespace abc = a_big_namespace;
abc::test();
}
Additionally I would like to be able to use the alias for function parameters. I haven't found a work-around for that.
void fn(abc::testType tt) {
abc::test(tt);
}
Is there a way to do what I want?
EDIT: my solution
I found that I didn't need unnamed namespace for my particular problem and can simply do this:
namespace myspace
{
namespace abc = a_big_namespace;
struct MyClass
{
void fn(abc::testType tt) {
abc::test(tt);
}
};
}
To switch to the other library, which is what my alias namespace refers to I just change the alias. This method even allows me to have the same class in a single file twice, each time refering to a different library.
Thanks for all your help.
Namespace alias in the class definition is illegal, as specified by the language specification.
Its allowed in only in namespace scope or function scope.
You can make alias at namespace scope. But that will be make permanent alias which can be used from other files as well. But the solution is simple : you can use unnamed namespace to prevent alias (and therefore all symbols from the big namespace) from being visible from other files. This is how it can be done:
//MyFile.cpp
namespace myspace
{
namespace //this is unnamed namespace
{
namespace abc = a_big_namespace;
}
struct MyClass
{
void fn()
{
abc::test(); //don't worry, this will work!
}
};
}
//OtherFile.cpp
myspace::abc::test(); //error - that means, prevention worked.
The alias is not visible from other files. When compiling OtherFile.cpp, GCC (4.5.0) says,
'myspace::abc' has not been declared
That proves the alias abc is visible only in MyFile.cpp. Thanks to unnamed namespace.
Demo : http://www.ideone.com/2zyNI (though it doesn't demonstrate OtherFile concept. I cannot have more than one file at ideone.com)
The scope of a namespace alias is a code block.
So you can put it in any code block.
BUT, you can't put it inside a class, because that will mean it's a member of the class.
A namespace alias can't be a member.
More about namespace aliases:
What is the scope of a namespace alias in C++?
Namespaces
It works if you declare the alias outside of the struct.
You can of course also put the alias outside the class:
namespace abc = a_big_namespace;
struct MyClass {
void fn()
{ abc::test(); }
};