インライン名前空間は、シンボルのバージョン管理に似たライブラリのバージョン管理機能ですが、特定のバイナリ実行可能形式(つまり、プラットフォーム固有)の機能ではなく、純粋にC ++ 11レベル(つまり、クロスプラットフォーム)で実装されます。
これは、ライブラリの作成者がネストされた名前空間を、そのすべての宣言が周囲の名前空間にあるかのように見せて動作させることができるメカニズムです(インラインの名前空間はネストできるため、「よりネストされた」名前は最初の非-インライン名前空間と、それらの宣言が間にある名前空間のいずれかにあるかのように見えて動作します)。
例として、のSTL実装について考えてみvector
ます。C ++の最初からインライン名前空間があった場合、C++98ではヘッダーは次の<vector>
ようになります。
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
の値に応じて__cplusplus
、いずれかのvector
実装が選択されます。コードベースがC++98より前の時代に書かれていて、コンパイラをアップグレードするときにC ++ 98バージョンがvector
問題を引き起こしていることがわかった場合、「すべて」は、での参照を見つけることですstd::vector
。コードベースを。に置き換えますstd::pre_cxx_1997::vector
。
次の標準が登場すると、STLベンダーは手順をもう一度繰り返し、サポートstd::vector
付きの新しい名前空間emplace_back
(C ++ 11が必要)を導入し、その1つのiffをインライン化し__cplusplus == 201103L
ます。
では、なぜこれに新しい言語機能が必要なのですか?同じ効果を得るために、私はすでに次のことを行うことができますね?
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
の値に応じて、__cplusplus
どちらかの実装を取得します。
そして、あなたはほとんど正しいでしょう。
次の有効なC++98ユーザーコードを検討してください(std
すでにC ++ 98の名前空間に存在するテンプレートを完全に特殊化することが許可されています)。
// 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
これは完全に有効なコードであり、ユーザーは、STL(のコピー)にあるものよりも効率的な実装を明らかに知っているタイプのセットに対して、独自のベクトルの実装を提供します。
ただし、テンプレートを特殊化する場合は、それが宣言された名前空間で行う必要があります。標準では、それはvector
名前空間で宣言されstd
ているため、ユーザーはここで型を特殊化することを当然期待しています。
このコードは、バージョン管理さstd
れていない名前空間またはC ++ 11インライン名前空間機能で機能しますが、を使用したバージョン管理のトリックでは機能しません。これは、定義された実際の名前空間が直接ではなかっusing namespace <nested>
たという実装の詳細を公開するためです。vector
std
ネストされた名前空間を検出できる他の穴がありますが(以下のコメントを参照)、インライン名前空間はそれらすべてをプラグインします。そして、それがすべてです。将来的には非常に便利ですが、AFAIK the Standardは、独自の標準ライブラリのインライン名前空間名を規定していません(ただし、これについて間違っていることが証明されることを望んでいます)。したがって、サードパーティライブラリにのみ使用できます。標準自体(コンパイラベンダーが名前空間に同意しない限り)。