C++ inline Namespace: Versioning, API Evolution, and ADL
이 글의 핵심
inline namespace in C++11+: lifting names into the parent namespace, API versioning, ABI notes, and differences from anonymous namespaces.
What is an inline namespace?
Names inside an inline namespace are also found as if they were declared in the enclosing namespace.
namespace MyLib {
inline namespace v2 {
void func() {
std::cout << "v2" << std::endl;
}
}
}
// Both work
MyLib::func(); // v2
MyLib::v2::func(); // v2
Versioning
namespace MyLib {
namespace v1 {
class Widget {
int data;
};
}
inline namespace v2 {
class Widget {
int data;
std::string name;
};
}
}
// Default is v2
MyLib::Widget w; // v2::Widget
// Explicit v1
MyLib::v1::Widget w1;
Practical examples
Example 1: API versions
namespace MyAPI {
namespace v1 {
void process(int x) {
std::cout << "v1: " << x << std::endl;
}
}
inline namespace v2 {
void process(int x, int y = 0) {
std::cout << "v2: " << x << ", " << y << std::endl;
}
}
}
int main() {
MyAPI::process(10); // v2
MyAPI::v1::process(10); // v1
}
Example 2: ABI selection
namespace MyLib {
#if MYLIB_VERSION >= 2
inline namespace v2 {
#else
inline namespace v1 {
#endif
class Data {
// version-specific layout
};
#if MYLIB_VERSION >= 2
}
#else
}
#endif
}
Example 3: Experimental vs stable
namespace MyLib {
inline namespace stable {
void reliableFunc() {
std::cout << "stable" << std::endl;
}
}
namespace experimental {
void newFunc() {
std::cout << "experimental" << std::endl;
}
}
}
int main() {
MyLib::reliableFunc(); // default
MyLib::experimental::newFunc(); // explicit
}
Example 4: Platform split
namespace MyLib {
#ifdef _WIN32
inline namespace windows {
void platformFunc() {
std::cout << "Windows" << std::endl;
}
}
#else
inline namespace posix {
void platformFunc() {
std::cout << "POSIX" << std::endl;
}
}
#endif
}
int main() {
MyLib::platformFunc();
}
Nested inline namespaces
namespace Outer {
inline namespace Middle {
inline namespace Inner {
void func() {
std::cout << "Inner" << std::endl;
}
}
}
}
Outer::func();
Outer::Middle::func();
Outer::Middle::Inner::func();
Common pitfalls
Pitfall 1: Name clashes
namespace MyLib {
inline namespace v1 {
void func() {}
}
inline namespace v2 {
void func() {} // error: ambiguous
}
}
Pitfall 2: Multiple inline siblings
// Bad
namespace MyLib {
inline namespace v1 {}
inline namespace v2 {} // clash
}
// Good: only one inline at a time
namespace MyLib {
namespace v1 {}
inline namespace v2 {}
}
Pitfall 3: ADL
namespace MyLib {
inline namespace v2 {
struct Data {};
void func(Data) {}
}
}
MyLib::Data d;
func(d); // ADL finds MyLib::v2::func
Pitfall 4: Documentation
namespace MyLib {
/// Current stable version
inline namespace v2 {
void func();
}
/// Legacy
namespace v1 {
void func();
}
}
Standard library
using namespace std::literals;
auto s = "hello"s; // std::string
using namespace std::chrono_literals;
auto duration = 5s;
Versioning strategy (API evolution)
inline namespace moves the default entry point while keeping older symbols addressable by explicit qualification.
- New major: make
v2inline; documentMyLib::v1::for legacy. - Breaking layout/signature: put new types in a new namespace and ship a migration guide.
- Deprecation: mark old APIs
[[deprecated]]while default routes to the new implementation. Only one inline child under a given parent at a time—there must be a single “default.”
ABI notes
ABI couples name mangling, calling conventions, and layout.
- Namespace names affect linker-visible symbols—consumers must link matching
v1/v2binaries. - Header-only changes against old binaries can surface as link errors or ODR violations—ship headers and binaries together.
- Platform
inline namespaceblocks can isolate platform-specific ABI behind one API name.
Library design checklist
- One public top-level namespace; prefer inline namespace vN over
inline namespace detail(detail is usually non-inline). - ADL: verify operators/swap resolve as intended when names lift.
- Release notes: state that
MyLib::Widgetis currentlyv2::Widget. - Tests: build against both explicit
v1paths and the default path.
C++17 inline variables vs inline namespace
- inline namespace: makes a namespace’s names appear in the parent (versioning / platform alias).
inlinevariables (C++17): ODR-safe header definitions of data (inline constexpr, etc.). Same keyword, different problems.
FAQ
Q1: When to use inline namespace?
A:
- API versioning
- ABI compatibility layers
- Experimental vs stable splits
Q2: Multiple inline namespaces?
A: Not as siblings under one parent—only one default.
Q3: Runtime cost?
A: None—purely compile-time name lookup.
Q4: Legacy code?
A: Call explicit v1:: paths.
Q5: Standard library?
A: inline literal namespaces are a familiar example.
Q6: Learning resources?
A:
- Effective Modern C++
- C++11 standard text
- API Design for C++
Related posts (internal links)
Practical tips
Debugging
- Warnings first
Performance
- Profile
Code review
- Conventions
Practical checklist
Before coding
- Right approach?
- Maintainable?
- Performance?
While coding
- Warnings?
- Edge cases?
- Errors?
At review
- Intent?
- Tests?
- Docs?
Keywords
C++, inline namespace, namespace, C++11, versioning
Related posts
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ ADL | ‘Argument Dependent Lookup’ 가이드
- C++ 컴파일 타임 프로그래밍 | constexpr·consteval·if constexpr 완벽 가이드
- C++ constexpr 함수 | ‘컴파일 타임 함수’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, inline namespace, Namespace, C++11, API Versioning 등으로 검색하시면 이 글이 도움이 됩니다.