Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are inline namespaces for?

C++11 allows inline namespaces, all members of which are also automatically in the enclosing namespace. I cannot think of any useful application of this -- can somebody please give a brief, succinct example of a situation where an inline namespace is needed and where it is the most idiomatic solution?

(Also, it is not clear to me what happens when a namespace is declared inline in one but not all declarations, which may live in different files. Isn't this begging for trouble?)

like image 393
Walter Avatar asked Jun 13 '12 13:06

Walter


People also ask

What is the main purpose of the namespace?

A namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it. Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.

What are the benefits of using namespaces?

Advantages of namespace In one program, namespace can help define different scopes to provide scope to different identifiers declared within them. By using namespace - the same variable names may be reused in a different program.

What is the point of an unnamed namespace?

Unnamed Namespaces They are directly usable in the same program and are used for declaring unique identifiers. In unnamed namespaces, name of the namespace in not mentioned in the declaration of namespace. The name of the namespace is uniquely generated by the compiler.

Can you use two namespaces C++?

You can have the same name defined in two different namespaces, but if that is true, then you can only use one of those namespaces at a time. However, this does not mean you cannot use the two namespace in the same program. You can use them each at different times in the same program.


2 Answers

Inline namespaces are a library versioning feature akin to symbol versioning, but implemented purely at the C++11 level (ie. cross-platform) instead of being a feature of a specific binary executable format (ie. platform-specific).

It is a mechanism by which a library author can make a nested namespace look and act as if all its declarations were in the surrounding namespace (inline namespaces can be nested, so "more-nested" names percolate up all the way to the first non-inline namespace and look and act as if their declarations were in any of the namespaces in between, too).

As an example, consider the STL implementation of vector. If we had inline namespaces from the beginning of C++, then in C++98 the header <vector> might have looked like this:

namespace std {  #if __cplusplus < 1997L // pre-standard C++     inline #endif      namespace pre_cxx_1997 {         template <class T> __vector_impl; // implementation class         template <class T> // e.g. w/o allocator argument         class vector : __vector_impl<T> { // private inheritance             // ...         };     } #if __cplusplus >= 1997L // C++98/03 or later                          // (ifdef'ed out b/c it probably uses new language                          // features that a pre-C++98 compiler would choke on) #  if __cplusplus == 1997L // C++98/03     inline #  endif      namespace cxx_1997 {          // std::vector now has an allocator argument         template <class T, class Alloc=std::allocator<T> >         class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good             // ...         };          // and vector<bool> is special:         template <class Alloc=std::allocator<bool> >         class vector<bool> {             // ...         };      };  #endif // C++98/03 or later  } // namespace std 

Depending on the value of __cplusplus, either one or the other vector implementation is chosen. If your codebase was written in pre-C++98 times, and you find that the C++98 version of vector is causing trouble for you when you upgrade your compiler, "all" you have to do is to find the references to std::vector in your codebase and replace them by std::pre_cxx_1997::vector.

Come the next standard, and the STL vendor just repeats the procedure again, introducing a new namespace for std::vector with emplace_back support (which requires C++11) and inlining that one iff __cplusplus == 201103L.

OK, so why do I need a new language feature for this? I can already do the following to have the same effect, no?

namespace std {      namespace pre_cxx_1997 {         // ...     } #if __cplusplus < 1997L // pre-standard C++     using namespace pre_cxx_1997; #endif  #if __cplusplus >= 1997L // C++98/03 or later                          // (ifdef'ed out b/c it probably uses new language                          // features that a pre-C++98 compiler would choke on)      namespace cxx_1997 {         // ...     }; #  if __cplusplus == 1997L // C++98/03     using namespace cxx_1997; #  endif  #endif // C++98/03 or later  } // namespace std 

Depending on the value of __cplusplus, I get either one or the other of the implementations.

And you'd be almost correct.

Consider the following valid C++98 user code (it was permitted to fully specialize templates that live in namespace std in C++98 already):

// I don't trust my STL vendor to do this optimisation, so force these  // specializations myself: namespace std {     template <>     class vector<MyType> : my_special_vector<MyType> {         // ...     };     template <>     class vector<MyOtherType> : my_special_vector<MyOtherType> {         // ...     };     // ...etc... } // namespace std 

This is perfectly valid code where the user supplies its own implementation of a vector for a set of type where she apparently knows a more efficient implementation than the one found in (her copy of) the STL.

But: When specializing a template, you need to do so in the namespace it was declared in. The Standard says that vector is declared in namespace std, so that's where the user rightfully expects to specialize the type.

This code works with a non-versioned namespace std, or with the C++11 inline namespace feature, but not with the versioning trick that used using namespace <nested>, because that exposes the implementation detail that the true namespace in which vector was defined was not std directly.

There are other holes by which you could detect the nested namespace (see comments below), but inline namespaces plug them all. And that's all there is to it. Immensely useful for the future, but AFAIK the Standard doesn't prescribe inline namespace names for its own standard library (I'd love to be proven wrong on this, though), so it can only be used for third-party libraries, not the standard itself (unless the compiler vendors agree on a naming scheme).

like image 92
Marc Mutz - mmutz Avatar answered Oct 11 '22 11:10

Marc Mutz - mmutz


http://www.stroustrup.com/C++11FAQ.html#inline-namespace (a document written by and maintained by Bjarne Stroustrup, who you'd think should be aware of most motivations for most C++11 features.)

According to that, it is to allow versioning for backward-compatibility. You define multiple inner namespaces, and make the most recent one inline. Or anyway, the default one for people who don't care about versioning. I suppose the most recent one could be a future or cutting-edge version which is not yet default.

The example given is:

// file V99.h: inline namespace V99 {     void f(int);    // does something better than the V98 version     void f(double); // new feature     // ... }  // file V98.h: namespace V98 {     void f(int);    // does something     // ... }  // file Mine.h: namespace Mine { #include "V99.h" #include "V98.h" }  #include "Mine.h" using namespace Mine; // ... V98::f(1);  // old version V99::f(1);  // new version f(1);       // default version 

I don't immediately see why you don't put using namespace V99; inside namespace Mine, but I don't have to entirely understand the use-case in order to take Bjarne's word for it on the committee's motivation.

like image 33
Steve Jessop Avatar answered Oct 11 '22 12:10

Steve Jessop