これは、既存のコードをリファクタリングするというよりも、新しいコードに関するものだと認識していますが、そのような場合に呼び出される特別なヘッダーを使用するのが好きX_fwd.hpp
です。
// X_def.hpp
namespace B
{
struct X {};
}
namespace A
{
// NOT: using namespace B; // does not participate in ADL!
typedef ::B::X X; // OR: using ::B::X;
}
// X_fwd.hpp
namespace A { struct X; }
// some file needing declaration of X
#include <X_fwd.hpp>
これにより、前方宣言を見つけるのがはるかに簡単になり、変更が 1 か所だけに分離されるため (DRY...)、事後にそれらを変更することも容易になります。
注1typedef
:知る限り、Peter Woodのaの回答とあなたのusing
宣言の使用の間に技術的な違いはありません。これらはArgument-Dependent-Lookupによって無視されるため、using
ディレクティブが問題を引き起こす可能性があることに注意してください。さらに悪いことに、新しい名前空間をもうプルしていないため、コードの一部が間違った関数オーバーロードを暗黙のうちに呼び出すことさえあります!using namespace B;
B
注2:質問へのコメントで、Ideoneの例が示されました。これは、名前空間内の名前検索に関する微妙な点をうまく示しています。ドラフトStandard、セクション3.4.3.2 Namespace members [namespace.qual]、節 2から引用するには
名前空間 X と名前 m の場合、名前空間で修飾されたルックアップ セット S(X, m) は次のように定義されます。 (7.3.1)。S'(X, m) が空でない場合、S(X, m) は S'(X, m) です。それ以外の場合、S(X, m) は、X の using ディレクティブによって指定されたすべての名前空間 Ni とそのインライン名前空間セットの S(Ni, m) の和集合です。
これは、次のトリッキーなあいまいさを説明しています
namespace A
{
struct X1{};
struct X2{};
}
namespace B
{
using A::X1; // OK: lookup-set is both namespace A and B, and a single unique name is found (at this point!)
struct X1; // OK: lookup-set is namespace B, and a single unique name is found
struct X2; // OK: lookup-set is namespace B, and a single unique name is found
using A::X2; // error: lookup-set is both namespace A and B, and no unique name is found (at this point!)
}
したがって、名前空間内に同じ名前を持つ直接宣言と using 宣言の両方を持つことの有効性は、順序に依存します。したがって、fwd ヘッダー ファイル内の単一の宣言の利便性。