我意识到这更多是关于新代码而不是重构现有代码,但我喜欢使用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>
这使得查找前向声明以及事后更改它们变得更加容易,因为更改仅在一个地方隔离(DRY ...)。
注意1typedef
:AFAIK,使用 Peter Wood 的 a 答案和您的using
声明之间没有技术区别。请注意,using
指令using namespace B;
可能会导致麻烦,因为Argument-Dependent-Lookup会忽略这些指令。更糟糕的是,您的某些代码甚至可能会默默地调用错误的函数重载,因为您不再拉入新的命名空间B
!
注意2 :在问题的评论中,给出了一个Ideone示例。这很好地说明了名称空间内名称查找的一个微妙之处:引用标准草案,第3.4.3.2 节命名空间成员 [namespace.qual],第 2节
对于命名空间 X 和名称 m,命名空间限定查找集 S(X, m) 定义如下: 令 S'(X, m) 是 X 中所有 m 声明的集合和 X 的内联命名空间集(7.3.1)。如果 S'(X, m) 不为空,则 S(X, m) 为 S'(X, m);否则,S(X, m) 是 S(Ni, m) 的并集,用于通过 X 中的 using 指令指定的所有命名空间 Ni 及其内联命名空间集。
这解释了以下棘手的歧义
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 头文件中进行单个声明很方便。