[2026] 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. 아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
namespace MyLib {
inline namespace v2 {
void func() {
std::cout << "v2" << std::endl;
}
}
}
// Both work
MyLib::func(); // v2
MyLib::v2::func(); // v2
Versioning
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
namespace MyLib {
inline namespace v1 {
void func() {}
}
inline namespace v2 {
void func() {} // error: ambiguous
}
}
Pitfall 2: Multiple inline siblings
아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 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
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
namespace MyLib {
inline namespace v2 {
struct Data {};
void func(Data) {}
}
}
MyLib::Data d;
func(d); // ADL finds MyLib::v2::func
Pitfall 4: Documentation
아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
namespace MyLib {
/// Current stable version
inline namespace v2 {
void func();
}
/// Legacy
namespace v1 {
void func();
}
}
Standard library
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
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?