What are inline namespaces for?
Asked Answered
C

6

427

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?)

Coper answered 13/6, 2012 at 13:46 Comment(0)
K
407

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).

Killen answered 13/6, 2012 at 15:35 Comment(24)
+1 for explaining why using namespace V99; doesn't work in Stroustrup's example.Pauiie
I suppose that versioning in the standard libraries in a standard way, is limited compared with 3rd party versioning. If C++21 vector is no good for me, and I need C++11 vector, then that might be because of a breaking change in C++21. But it might be because of an implementation detail that I shouldn't have relied on in the first place. The standard can't require that every C++21 implementation provides a std::cxx_11::vector that's bug compatible with any past std::vector from the same vendor. Third party libraries can undertake to do that, if they think it's worth it for them.Pauiie
And similarly, if I start a brand new C++21 implementation from scratch, then I don't want to be burdened implementing a lot of old nonsense in std::cxx_11. Not every compiler will always implement all old versions of the standard libraries, even though it's tempting at the moment to think that it would be very little burden to require existing implementations to leave in the old when they add the new, since in fact they all are anyway. I suppose what the standard could usefully have done is made it optional, but with a standard name if present.Pauiie
just a little curiosity about your usage of the predefined macro __cplusplus. Does the standard say anything about this? gcc, for example (version 4.3.2) simply sets it to 1, regardless of what you set for -std.Coper
@Walter: g++ -std=c++11 -x c++ -dM -E - < /dev/null says __cplusplus is defined as 201103L. Cf. also 16.8 [cpp.predefined].Killen
@Mark okay for gcc 4.7.0, but for earlier versions (with -std=c++0x), we get #define __cplusplus 1, which implies that using this macro is rather useless for distinguishing pre 2011 standards.Coper
@Walter: Confirmed with 4.3. Also w/o -std=c++0x. That probably just means that the GCC developers think they never implemented full C++98 before 4.7 (and they're right, their template name resolution wasn't standards-conforming until 4.7) :)Killen
That's not all there is to it. ADL also was a reason (ADL won't follow using directives), and name lookup too. (using namespace A in a namespace B makes names in namespace B hide names in namespace A if you look for B::name - not so with inline namespaces).Garnishee
libc++ implements the standard library using inline namespaces for versioning. I think this is a perfectly conformant design decision since I don't think it will break any conformant programs. There are non-conformant programs that break though, such as those that try to forward declare entities in the std namespace.Dudgeon
Why don't just use ifdefs for the full vector implementation? All implementations would be in one namespace but only one of them will be defined after preprocessingDickie
@sasha.sochka, because in this case you can't use other implementations. They will be removed by preprocessor. With inline namespaces you can use any implementation you want by specifying fully qualified name (or using keyword).Collocutor
Also note that inline template was based on a GCC extension (I pretty sure), were you could add the add __attribute__((__strong__)) to a using namespace declaration which would exactly fix the problems with specializations and ADL. This feature was added to GCC specifically to write their STL implementation, and is why it was included in the C++11, except with the much clearer syntax of inline templates. (having using namespace-statements which ADL and specializations can traverse "backwards" through is inviting a whole lot of problems)Epagoge
In the first code quote, should it be template <class Alloc=std::allocator<bool> > class vector<bool, Alloc> { /*...*/ };?Sailcloth
Can this feature be used to maintain binary compatibility in shared libraries as well (e.g. adding the new c++11 vector and keeping inline namespace at c++98) ? If so, could you please add an example of this, and when this does and does not work?Exemplificative
@meastp: I believe the preferred way on SO is to ask a question. That way, you reach more people that may answer (and you'd already have that answer by now).Killen
@MarcMutz-mmutz Ok, I have created a question with an example. Please have a look at it :) stackoverflow.com/questions/29764869Exemplificative
@MarcMutz-mmutz This post is 3 years old by now so you probably already know about it, but yes there are inline namespaces prescribed by the standard (all since C++14 regarding user-defined literals), namely: std::literals itself, std::literals::chrono_literals, std::literals::string_literals and std::literals::complex_literals.Amil
@MaxTruxa: Me comment was about names for inline namespaces to version the std library. std::literals is not for versioning the library.Killen
@MarcMutz-mmutz "std::literals is not for versioning the library" Ok, but why are those inline then? If not for versioning, what is gained here? Because the namespaces of std::literals::chrono_literals` and std::literals::string_literals both contain operator""s, why do they not conflict with each other, being both inline?Alongshore
@Alongshore they don't conflict because they are different overloads. The chrono one expects unsigned long long, the string one expects a Char pointer and a length as size_t.Cadi
@Alongshore I guess the gain is easy of use. With a single expression you can import just a group of literals, all literals or the whole std namespace including all literals.Cadi
Are you sure the specialization does not work with the versioning trick that used using namespace <nested>? This code compiles under Clang but fails under GCC.Teasel
I believe both libc++ and libstdc++ use inline namespace in order to deal with the ABI compatibility.Venegas
@MarcMutz-mmutz There is no inline namespae in your first code snippet when the __cplusplus is 201103L. How the instances of std::vector could be defined?Denotation
P
89

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.

Pauiie answered 13/6, 2012 at 13:52 Comment(9)
So in fact the last f(1) version would be called from the inline V99 namespace?Varlet
@EitanT: yes, because the global namespace has using namespace Mine;, and the Mine namespace contains everything from the inline namespace Mine::V99.Pauiie
but for this to work, I would need to add inline to file V99.h. What happens when file V100.h comes about, declaring inline namespace V100, and I include it too into Mine? Which f(int) is called by f(1)?Coper
@Walter: you remove inline from file V99.h in the release that includes V100.h. You also modify Mine.h at the same time, of course, to add an extra include. Mine.h is part of the library, not part of the client code.Pauiie
of course, but that assumes that whoever installs V100.h also has to re-install a new version of V99.h. If this is so, why then the whole thing, rather than just updating all of V99.h (even the stuff that is not improved)? I still don't see the whole point.Coper
@walter: they're not installing V100.h, they're installing a library called "Mine". There are 3 header files in version 99 of "Mine" -- Mine.h, V98.h and V99.h. There are 4 header files in version 100 of "Mine" -- Mine.h, V98.h, V99.h and V100.h. The arrangement of the header files is an implementation detail that is irrelevant to users. If they discover some compatibility problem which means they need to use specifically Mine::V98::f from some or all of their code, they can mix calls to Mine::V98::f from old code with calls to Mine::f in newly-written code.Pauiie
Hmm. But if "they" install also Mine.h etc, then why not inserting using namespace V100 into Mine.h (as you ask yourself)? This is still mysterious.Coper
@Coper As the other answer mentions, templates need to be specialised in the namespace they're declared in, not a namespace using the one they're declared in. While it looks weird, the way it's done there allows you to specialise templates in Mine, instead of having to specialise in Mine::V99 or Mine::V98.Tosh
It would be good to clarify in the answer which version // default version resolves to in the example (old/new) and how it is determined.Chromaticity
P
30

In addition to all the other answers.

Inline namespace can be used to encode ABI information or Version of the functions in the symbols. It is due to this reason they are used to provide backward ABI compatibility. Inline namespaces let you inject information into the mangled name (ABI) without altering the API because they affect linker symbol name only.

Consider this example:

Suppose you write a function Foo that takes a reference to an object say bar and returns nothing.

Say in main.cpp

struct bar;
void Foo(bar& ref);

If you check your symbol name for this file after compiling it into an object.

$ nm main.o
T__ Z1fooRK6bar 

The linker symbol name may vary but it will surely encode the name of function and argument types somewhere.

Now, it could be that bar is defined as:

struct bar{
   int x;
#ifndef NDEBUG
   int y;
#endif
};

Depending upon Build type, bar can refer to two different types/layouts with same linker symbols.

To prevent such behavior we wrap our struct bar into an inline namespace, where depending upon the Build type the linker symbol of bar will be different.

So, we could write:

#ifndef NDEBUG
inline namespace rel { 
#else
inline namespace dbg {
#endif
struct bar{
   int x;
#ifndef NDEBUG
   int y;
#endif
};
}

Now if you look at the object file of each object you build one using release and other with debug flag. You will find that linker symbols include inline namespace name as well. In this case

$ nm rel.o
T__ ZROKfoo9relEbar
$ nm dbg.o
T__ ZROKfoo9dbgEbar

Linker Symbol names may be different.

Notice presence of rel and dbg in the symbol names.

Now, if you try to link debug with release mode or vise-versa you will get a linker error as contrary to runtime error.

Pyromagnetic answered 21/6, 2019 at 1:11 Comment(1)
Yes, that makes sense. So this is more for library implementers and the like.Coper
T
10

So to sum up the main points, using namespace v99 and inline namespace were not the same, the former was a workaround to version libraries before a dedicated keyword (inline) was introduced in C++11 which fixed the problems of using using, whilst providing the same versioning functionality. Using using namespace used to cause problems with ADL (although ADL now appears to follow using directives), and out-of-line specialisation of a library class / function etc. by the user wouldn't work if done outside of the true namespace (whose name the user wouldn't and shouldn't know, i.e. the user would have to use B::abi_v2:: rather than just B:: for the specialisation to resolve).

//library code
namespace B { //library name the user knows
    namespace A { //ABI version the user doesn't know about
        template<class T> class myclass{int a;};
    }
    using namespace A; //pre inline-namespace versioning trick
} 

// user code
namespace B { //user thinks the library uses this namespace
    template<> class myclass<int> {};
}

This will show a static analysis warning first declaration of class template specialization of 'myclass' outside namespace 'A' is a C++11 extension [-Wc++11-extensions]. But if you make namespace A inline, then the compiler correctly resolves the specialisation. Although, with the C++11 extensions, the issue goes away.

Out-of-line definitions don't resolve when using using; they have to be declared in a nested/non-nested extension namespace block (which means the user needs to know the ABI version again, if for whatever reason they were permitted to provide their own implementation of a function).

#include <iostream>
namespace A {
    namespace B{
        int a;
        int func(int a);
        template<class T> class myclass{int a;};
        class C;
        extern int d;
    } 
    using namespace B;
} 
int A::d = 3; //No member named 'd' in namespace A
class A::C {int a;}; //no class named 'C' in namespace 'A' 
template<> class A::myclass<int> {}; // works; specialisation is not an out-of-line definition of a declaration
int A::func(int a){return a;}; //out-of-line definition of 'func' does not match any declaration in namespace 'A'
namespace A { int func(int a){return a;};} //works
int main() {
    A::a =1; // works; not an out-of-line definition
}

The issue goes away when making B inline.

The other functionality inline namespaces have is allowing the library writer to provide a transparent update to the library 1) without forcing the user to refactor code with the new namespace name and 2) preventing lack of verbosity and 3) providing abstraction of API-irrelevant details, whilst 4) giving the same beneficial linker diagnostics and behaviour that using a non-inline namespace would provide. Let's say you're using a library:

namespace library {
    inline namespace abi_v1 {
        class foo {
        } 
    }
}

It allows the user to call library::foo without needing to know or include the ABI version in the documentation, which looks cleaner. Using library::abiverison129389123::foo would look dirty.

When an update is made to foo, i.e. adding a new member to the class, it will not affect existing programs at the API level because they wont already be using the member AND the change in the inline namespace name will not change anything at the API level because library::foo will still work.

namespace library {
    inline namespace abi_v2 {
        class foo {
            //new member
        } 
    }
}

However, for programs that link with it, because the inline namespace name is mangled into symbol names like a regular namespace, the change will not be transparent to the linker. Therefore, if the application is not recompiled but is linked with a new version of the library, it will present a symbol abi_v1 not being found error, rather than it actually linking and then causing a mysterious logic error at runtime due to ABI incompatibility. Adding a new member will cause ABI compatibility due to the change in type definition, even if it doesn't affect the program at compile time (API level).

In this scenario:

namespace library {
    namespace abi_v1 {
        class foo {
        } 
    }

    inline namespace abi_v2 {
        class foo {
            //new member
        } 
    }
}

Like using 2 non-inline namespaces, it allows for a new version of the library to be linked without needing to recompile the application, because abi_v1 will be mangled in one of the global symbols and it will use the correct (old) type definition. Recompiling the application would however cause the references to resolve to library::abi_v2.

Using using namespace is less functional than using inline (in that out of line definitions don't resolve) but provides the same 4 advantages as above. But the real question is, why continue to use a workaround when there is now a dedicated keyword to do it. It's better practice, less verbose (have to change 1 line of code instead of 2) and makes the intention clear.

Toback answered 28/3, 2020 at 13:50 Comment(0)
D
6

I actually discovered another use for inline namespaces.

With Qt, you get some extra, nice features using Q_ENUM_NS, which in turn requires that the enclosing namespace has a meta-object, which is declared with Q_NAMESPACE. However, in order for Q_ENUM_NS to work, there has to be a corresponding Q_NAMESPACE in the same file⁽¹⁾. And there can only be one, or you get duplicate definition errors. This, effectively, means that all of your enumerations have to be in the same header. Yuck.

Or... you can use inline namespaces. Hiding enumerations in an inline namespace causes the meta-objects to have different mangled names, while looking to users like the additional namespace doesn't exist⁽²⁾.

So, they're useful for splitting stuff into multiple sub-namespaces that all look like one namespace, if you need to do that for some reason. Of course, this is similar to writing using namespace inner in the outer namespace, but without the DRY violation of writing the name of the inner namespace twice.


  1. It's actually worse than that; it has to be in the same set of braces.

  2. Unless you try to access the meta-object without fully qualifying it, but the meta-object is hardly ever used directly.

Demoss answered 27/8, 2019 at 20:24 Comment(2)
Can you sketch that with a skeleton of code? (ideally w/o explicit reference to Qt). It all sounds rather involved/unclear.Coper
Not... easily. The reason separate namespaces are needed has to do with Qt implementation details. TBH, it's hard to imagine a situation outside of Qt that would have the same requirements. However, for this Qt-specific scenario, they're darned useful! See gist.github.com/mwoehlke-kitware/… or github.com/Kitware/seal-tk/pull/45 for an example.Demoss
C
6

Inline namespaces can also be used to provide fine(r)-grained access to features/names within namespaces.

This is used in std::literals. The literals namespaces in std are all inline namespaces, so that:

  • if you use using namespace std; somewhere, you also get access to all user defined literals in the std.
  • but if you just need a set of udl in you local code, you can also do using namespace std::literals::string_literals; and you will just get the udl symbols defined in that namespace.

This seems a useful technique for symbols that you would want to access unqualified (udl, operators, etc.) where you can just bundle them up in an inline namespace so that you can do a specific using on just that (sub-) namespace instead of the namespace of the whole library.

Clinkstone answered 2/2, 2022 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.