What Are Inline Namespaces For

What are inline namespaces for?

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

C++11 inline namespace vs embedding the types directly in the enclosing namespace

The main motivation for C++ inline namespaces does indeed involve versioning. You are on the right track with your understanding, except for the final sentence in your question:

My preference would even rename "current" to "deprecated"

The whole idea of using inline namespaces is that the namespace names aren't changing -- rather, this feature allows for the namespace names to not need to change; existing names can live on forever without requiring much change to code.

Instead, at the time a version release is made (when what we used to think of as "current features" now become "deprecated features"), the namespace names can stay the same but their default status gets updated.

Let's see this in code:

namespace MyProject {
namespace Version1 {
void BoringStableFunction() {...}
}
inline namespace Version2 {
void BoringStableFunction() {...}
void LatestAndGreatest(int x) {...}
}
}

The clients of this software probably will most often be using it by simply calling MyProject::BoringStableFunction() and maybe MyProject::LatestAndGreatest(11), perhaps without even knowing that two separate versions of MyProject exist. And that convenience can be a good thing. If a client does know that there were two different versions, and intentionally wants to use the old one (before LatestAndGreatest() had been invented), he can still do so by calling MyProject::Version1::BoringStableFunction().

Note that a client is allowed to write his code as MyProject::Version2::BoringStableFunction(). Doing so is the client essentially saying "I want to call that current #2 version, and I want that implementation which I'm using to stay the same -- even if that MyProject project gets updated later on"

Notice how I can perform additional development without affecting any of my existing clients:

namespace MyProject {
namespace Version1 {
void BoringStableFunction() {...}
}
inline namespace Version2 {
void BoringStableFunction() {...}
void LatestAndGreatest(int x) {...}
}
namespace Version3 {
void BoringStableFunction() {...}
void LatestAndGreatest(std::string x) {...}
}
}

When I'm ready to release my changes to the general public, only this tiny edit needs to be made:

namespace MyProject {
namespace Version1 {
void BoringStableFunction() {...}
}
namespace Version2 {
void BoringStableFunction() {...}
void LatestAndGreatest(int x) {...}
}
inline namespace Version3 {
void BoringStableFunction() {...}
void LatestAndGreatest(std::string x) {...}
}
}

Most of the clients had been calling MyProject::BoringStableFunction(). Their code won't need to be edited; it is still syntactically valid. But they will now suddenly be taking advantage of any new implementation that I might have changed within BoringStableFunction().

If they had been so bold as to be using my MyProject::LatestAndGreatest(11), they will need to be informed that they now need to update their usage. So this demonstrates that, even with inline namespaces, thought still needs to be put into the contract between a programmer and his client.

Seeking clarification on inline namespace

Consider a stupid example:

#include <iostream>

namespace foo {
inline namespace v1 {
template <typename T>
void bar(T t) {
(void) t;
std::cout << "Generic bar\n";
}
}

template <>
void bar<int>(int v) {
(void) v;
std::cout << "Specialized bar\n";
}
}

int main() {
foo::bar(12);
foo::v1::bar(12);
foo::bar(12.0);
return 0;
}

If you run this, you'll get the following output:

Specialized bar
Specialized bar
Generic bar

This is because calling foo::bar with an int is specialized in foo, even though the default implementation exists in foo::v1.

This example is useless, but consider a scenario where you wanted to specialize a template function or class in an external library (including the stl). You don't know if vector is a member of std or std::cxx11 (libc++ uses std::__1 for many things). Since an inline namespace is a way to provide versioning at the API level (e.g., you change your inline namespace to v2 and leave v1 alone), this lets end-users specialize without knowing the details of the inlined namespaces.

What is the benefit of std::literals::.. being inline namespaces?

The user-defined literal s does not "clash" between seconds and string, even if they are both in scope, because they overload like any other pair of functions, on their different argument lists:

string  operator "" s(const char* str, size_t len);
seconds operator "" s(unsigned long long sec);

This is evidenced by running this test:

void test1()
{
using namespace std;
auto str = "text"s;
auto sec = 1s;
}

With using namespace std, both suffixes are in scope, and yet do not conflict with each other.

So why the inline namespace dance?

The rationale is to allow the programmer to expose as few std-defined names as desired. In the test above, I've "imported" the entire std library into test, or at least as much as has been #included.

test1() would not have worked had namespace literals not been inline.

Here is a more restricted way to use the literals, without importing the entire std:

void test2()
{
using namespace std::literals;
auto str = "text"s;
auto sec = 1s;
string str2; // error, string not declared.
}

This brings in all std-defined literals, but not (for example) std::string.

test2() would not work if namespace string_literals was not inline and namespace chrono_literals was not inline.

You can also choose to just expose the string literals, and not the chrono literals:

void test3()
{
using namespace std::string_literals;
auto str = "text"s;
auto sec = 1s; // error
}

Or just the chrono literals and not the string literals:

void test4()
{
using namespace std::chrono_literals;
auto str = "text"s; // error
auto sec = 1s;
}

Finally there is a way to expose all of the chrono names and the chrono_literals:

void test5()
{
using namespace std::chrono;
auto str = "text"s; // error
auto sec = 1s;
}

test5() requires this bit of magic:

namespace chrono { // hoist the literals into namespace std::chrono
using namespace literals::chrono_literals;
}

In summary, the inline namespaces are a tool to make all of these options available to the developer.

Update

The OP asks some good followup questions below. They are (hopefully) addressed in this update.

Is using namespace std not a good idea?

It depends. A using namespace is never a good idea at global scope in a header that is meant to be part of a general purpose library. You don't want to force a bunch of identifiers into your user's global namespace. That namespace belongs to your user.

A global scope using namespace can be ok in a header if the header only exists for the application you are writing, and if it is ok with you that you have all of those identifiers available for everything that includes that header. But the more identifiers you dump into your global scope, the more likely it is that they will conflict with something. using namespace std; brings in a bunch of identifiers, and will bring in even more with each new release of the standard. So I don't recommend using namespace std; at global scope in a header even for your own application.

However I could see using namespace std::literals or using namespace std::chrono_literals at global scope in a header, but only for an application header, not a library header.

I like to use using directives at function scope as then the import of identifiers is limited to the scope of the function. With such a limit, if a conflict does arise, it is much easier to fix. And it is less likely to happen in the first place.

std-defined literals will probably never conflict with one another (they do not today). But you never know...

std-defined literals will never conflict with user-defined literals because std-defined literals will never start with _, and user-defined literals have to start with _.

Also, for library developers, is it necessary (or good practice) to have no conflicting overloads inside several inline namespaces of a large library?

This is a really good question, and I posit that the jury is still out on this one. However I just happen to be developing a library that purposefully has conflicting user-defined literals in different inline namespaces!

https://github.com/HowardHinnant/date

#include "date.h"
#include "julian.h"
#include <iostream>

int
main()
{
using namespace date::literals;
using namespace julian::literals;
auto ymd = 2017_y/jan/10;
auto jymd = julian::year_month_day{ymd};
std::cout << ymd << '\n';
std::cout << jymd << '\n';
}

The above code fails to compile with this error message:

test.cpp:10:20: error: call to 'operator""_y' is ambiguous
auto ymd = 2017_y/jan/10;
^
../date/date.h:1637:1: note: candidate function
operator "" _y(unsigned long long y) NOEXCEPT
^
../date/julian.h:1344:1: note: candidate function
operator "" _y(unsigned long long y) NOEXCEPT
^

The _y literal is used to create year in this library. And this library has both a Gregorian calendar (in "date.h") and a Julian calendar (in "julian.h"). Each of these calendars has a year class: (date::year and julian::year). They are different types because the Gregorian year is not the same thing as a Julian year. But it is still convenient to name them both year and to give them both a _y literal.

If I remove the using namespace julian::literals; from the code above then it compiles and outputs:

2017-01-10
2016-12-28

which is a demonstration that 2016-12-28 Julian is the same day as 2017-01-10 Gregorian. And this is also a graphic demonstration that the same day can have different years in different calendars.

Only time will tell if my use of conflicting _ys will be problematic. To date it hasn't been. However not many people have used this library with non-Gregorian calendars.

Nested namespace definition when the enclosing namespace is inline

The fixit-hint for clang is misleading (since you cannot actually do the thing it is telling you to do), but the program is fine (although misleading, since it looks like you're declaring a non-inline namespace when you're really not - so the warning isn't entirely unreasonable).


Ignoring nested namespaces for the moment, this is actually fine:

inline namespace N { int i=0; };
namespace N { int j=1; };
int k=j;

The only rule we have, from [namespace.def]/3, is (emphasis mine):

The inline keyword may be used on a namespace-definition that extends a namespace only if it was previously used on the namespace-definition that initially declared the namespace-name for that namespace.

The wording is "only if", not "if and only if" - so you can't mark a namespace inline that was previously not marked... but if the first declaration of a namespace is inline, not every subsequent declaration has to be.

As noted in OP, clang warns on this anyway. Because it's kind of misleading.


But why can't we just stick a leading inline in there?

As described in the paper, the problem with allowing nested namespace with the leading namespace inline is that it leads to ambiguity for programmers:

inline namespace std::experimental::parallelism_v2;  // not immediately to reader,
// is std or parallelism_v2 inline?

And the same would be true if you harmonized the leading inline with the nested inline by putting it on the other side of namespace:

namespace inline std::experimental::parallelism_v2;  // immediately to reader?
// std or parallelism_v2 inline?

So it's imply not supported. If you want a nested namespace with the top-level namespace inline... you can't. The top-level namespace must be non-inline (I suppose we could've considered syntax like namespace ::inline N::inline M but that's just weird in its own way).



Inline namespaces and ambigous declarations

It looks like this was a pre clang 3.5 bug and there are two defect reports on this 812 and 861. The resolution is in 861 and adds the following to 3.4.3.2 [namespace.qual] (emphasis mine going forward):

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S'(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1 [namespace.def]). If S'(X,m) is not empty, S(X,m) is S'(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all non-inline namespaces Ni nominated by using-directives in X and its inline namespace set.

and the also relevant additions:

if S(X,m) is the empty set, the program is ill-formed. Otherwise, if S(X,m) has exactly one member, or if the context of the reference is a using-declaration (7.3.3 [namespace.udecl]), S(X,m) is the required set of declarations of m. Otherwise if the use of m is not one that allows a unique declaration to be chosen from S(X,m), the program is ill-formed.

It looks like the change was added pre C++11, this text is present in N3337.

C++ Does inlining a namespace implicitly inline its functions?

The simple answer is: no. You can absolutely define the functions in a separate cpp file. inline on a namespace basically makes it so that you don't need to specify the namespace name. For example, you can do outer::func() instead of outer::inner::func()

See [namespace.def]/5-7. There is no restrictions on where you must define the functions, and that it implicitly inlines them.

The error you are getting is in how you are compiling. Likely, you forgot to compile the .cpp file, or at least link it to where it is being called from.



Related Topics



Leave a reply



Submit