インラインネームスペースは、symbol versioningに類似したライブラリバージョン管理機能ですが、特定のバイナリ実行形式(つまりプラットフォーム固有)の機能ではなく、C++ 11レベル(つまりクロスプラットフォーム) 。
これは、ライブラリ作成者がネストされた名前空間を表示し、その宣言が周囲の名前空間にあるように動作させるメカニズムです(インラインネームスペースをネストすることができるので、 "ネストネスト"最初の非インラインネームスペースに移動し、その宣言が間にあるネームスペースのいずれかにあるかのように見て行動します)。
例として、vector
のSTL実装について考えてみましょう。我々はC++ 98のヘッダ<vector>
で、その後C++の初めから、インラインの名前空間を持っていた場合、このように見えたかもしれません:
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
実装が選択されています。あなたのコードベースがpre-C++ 98回で書かれていて、vector
のC++ 98バージョンがあなたのコンパイラをアップグレードするときに問題を引き起こしていることが判明した場合、「すべて」というのは、 std::vector
をコードベースに置き換えて、std::pre_cxx_1997::vector
に置き換えてください。
は、次の標準に来て、STLのベンダーは、単に(C++ 11が必要です)emplace_back
サポートでstd::vector
のための新しい名前空間を導入し、__cplusplus == 201103L
IFFその1をインライン化、もう一度手順を繰り返します。
これで新しい言語機能が必要なのはなぜですか。私はすでに同じ効果を得るために次のことをすることができますか?
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
の値に応じて、私は実装の1つまたは他のいずれかを取得します。
そして、あなたは、ほぼ正しいだろう。
// 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
これはどこのユーザー完全に有効なコードです:
は、次の有効なC++ 98ユーザーコードを(それが完全にすでにC++ 98で名前空間std
に住んでテンプレートを特化することが許可された)考えてみましょうSTLの(自分のコピーにある)ものよりも効率的な実装を明らかに知っている、一連のタイプのベクトルの独自の実装を提供しています。
しかし:テンプレートを専門とするとき、あなたはそれがで宣言された名前空間にそうする必要がある標準は、ユーザーが合法タイプを特化することを予測する場合には、ですのでvector
は、名前空間std
で宣言されていることを述べています。
すなわちにおけるvector
真の名前空間であることが確認された実装の詳細を公開するので、このコードは、非バージョンの名前空間std
有する、またはC++ 11インライン・ネームスペース機能ではなく、using namespace <nested>
を使用するバージョンのトリックと連携定義されたのはstd
ではありません。
は、ネストされた名前空間を(下のコメントを参照)を検出することができたことにより、他の穴がありますが、インライン名前空間には、それらをすべて接続します。そして、それがそこにあるのです。将来的には非常に便利ですが、AFAIK標準は独自の標準ライブラリのインラインネームスペース名を規定していません(私はこの点では間違っていることが分かりますが)。サードパーティのライブラリでのみ使用できます。コンパイラのベンダーが命名規則に同意しない限り、標準自体。
Stroustrupの例で 'using namespace V99; 'が動作しない理由を説明するため+1。 –
私は標準的な方法で標準ライブラリのバージョン管理は、サードパーティのバージョン管理と比較して制限されていると思います。もしC++ 21の 'vector'が私には役に立たず、C++ 11の' vector'が必要なら、それはC++ 21の急激な変化のせいかもしれません。しかし、それは私が最初に頼ってはいけない実装の詳細のためかもしれません。標準では、すべてのC++ 21実装が、同じベンダーの過去の 'std :: vector'とバグのある' std :: cxx_11 :: vector'を提供することを要求することはできません。サードパーティの図書館は、それが価値あると考えるならば、それを行うことができます。 –
同様に、まったく新しいC++ 21実装を開始すると、 'std :: cxx_11'に古いナンセンスをたくさん実装することに負担をかけたくありません。すべてのコンパイラが標準ライブラリのすべての古いバージョンを実装するわけではありませんが、現時点では新しいものを追加するときに既存の実装を古いものにする必要はほとんどありません。とにかくです。私は、標準が有益に行うことができたものはオプションであるが、存在する場合は標準の名前であると考えている。 –