C++11 - 인라인 이름 공간(inline namespace)
개요
이름 공간 내에 있는 기능을 투과해서 접근할 수 있는 기능이다. 즉 이름 공간(my_namespace) 안에 또 다른 이름 공간(features)을 inline로 선언하고 있으면 features에 정의된 기능을 my_namespace를 통해서 접근 할 수 있다.
#include <iostream>
namespace my_namespace {
inline namespace features {
void f() {
std::cout << "call f()" << std::endl;
}
}
}
int main()
{
my_namespace::features::f();
my_namespace::f(); // features 이름 공간을 생략했다.
}
문법
- 이름 공간의 inline 지정은 이름 있는 이름 공간과 이름 없는 이름 공간 양쪽에서 사용할 수 있다.
- inline 지정된 이름 공간을 “인라인 이름 공간(inline namespace)”이라고 부른다.
inline namespace my_namespace {}
inline namespace {}
- 인라인 이름 공간의 멤버는(이름 공간 안에 정의한 것) 이것의 외부 이름 공간의 구성원으로 사용할 수 있다.
- 인라인 이름 공간과 외부 이름 공간은 인수 종속의 이름 검색에서 검색되는 “관련 있는 이름 공간(associated namespace)” 이 된다
#include <iostream>
namespace ns1 {
class X {};
inline namespace ns2 {
class Y {};
void f(X)
{
std::cout << "call f()" << std::endl;
}
}
void g(Y)
{
std::cout << "call g()" << std::endl;
}
}
int main()
{
f(ns1::X()); // 「call f()」출력
g(ns1::Y()); // 「call g()」출력
g(ns1::ns2::Y()); // 「call g()」출력
}
- 인라인 이름 공간의 외부 이름 공간을 using 지시문을 지정하여 인라인 이름 공간의 구성원이 외부 이름 공간 멤버로 암시 적으로 삽입된다
#include <iostream>
namespace ns1 {
inline namespace ns2 {
void f()
{
std::cout << "call f()" << std::endl;
}
}
}
int main()
{
using namespace ns1;
f();
}
- 인라인 이름 공간의 멤버는 외부 이름 공간에서 외부 이름 공간의 멤버 인 것처럼 명시적으로 인스턴스화 및 명시적 특수화 수 있다.
#include <iostream>
namespace ns1 {
inline namespace ns2 {
template <class T>
struct X {
static constexpr int value = 0;
};
}
// 인라인 이름 공간에서 정의된 클래스 템플릿을 명시적으로 인스턴스화
template struct X<int>;
// 인라인 이름 공간에서 정의된 클래스트 템플릿을 명시적으로 특수화
template <>
struct X<void> {
static constexpr int value = 1;
};
}
int main()
{
std::cout << ns1::X<int>::value << std::endl; // 0 출력
std::cout << ns1::X<void>::value << std::endl; // 1 출력
std::cout << ns1::ns2::X<void>::value << std::endl; // 1 출력
}
- 인라인 이름 공간의 멤버와 외부 이름 공간의 멤버가 이름이 같은 경우 외부 이름 공간으로 이 멤버에 접근하면 이름 충돌로 에러가 된다.
namespace ns1 {
inline namespace ns2 {
int a;
}
int a;
}
int main()
{
ns1::a = 0; // 이름 충돌로 에러
//ns1::ns2::a = 0; // 이것은 ok
}
API 버저닝
- 인라인 이름 공간을 기본 버전으로 하고, 오래된 API를 원래의 이름 공간에 그대로 남겨 둘 수 있다.
기본 버전을 전환 할 때 기본 버전에 이름 공간을 인라인 이름 공간로 변경하고 기본 버전 이외의 이름 공간를 비 인라인 이름 공간로 변경한다.
따라서 바이너리 호환성을 유지하면서 버전 관리를 쉽게 할 수 있다.
#include <iostream>
namespace my_namespace {
namespace v1 {
void f()
{
std::cout << "v1" << std::endl;
}
}
inline namespace v2 {
void f()
{
std::cout << "v2" << std::endl;
}
}
}
int main()
{
my_namespace::v1::f(); // 오래된 버전의 API를 호출. v1 출력
my_namespace::v2::f(); // 버전을 명시적으로 지정하여 API를 호출. v2 출력
my_namespace::f(); // 기본 버전의 API를 호출. v2 출력
}
출처
- https://cpprefjp.github.io/lang/cpp11/inline_namespaces.html
이 글은 2017-01-02에 작성되었습니다.