我原来的班级结构类似于:
//def.h
namespace A
{
struct X {};
}
并在需要时转发声明:
//file that needs forward declarations
namespace A { struct X; }
经过一些重构后,X
被移到了另一个名称空间,但为了保持旧代码“工作”using
指令的使用:
//def.h
namespace B
{
struct X {};
}
namespace A
{
using ::B::X;
}
现在我们可以访问保留旧语法A::X
的同一个类,但前向声明会导致错误。第二个问题是我得到的错误消息并未指向前向声明的位置,并且查找/替换前向声明非常耗时。
现在我解决了问题(困难的方法)。
处理这种情况的最佳方法是什么?
IMO,using
根本不应该存在,并且所有使用X
的代码都应该被重构以容纳新的命名空间(这是一个解决方案),但不幸的是,这不是一个选项。
实际代码要复杂得多,这是一个简化的例子。
答案 0 :(得分:4)
我意识到这更多是关于新代码而不是重构现有代码,但我喜欢在这种情况下使用名为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 ...)。
NOTE1 :AFAIK,使用Peter Wood对typedef
和using
声明的回答之间没有技术差异。请注意,using
指令using namespace B;
可能会导致问题,因为 Argument-Dependent-Lookup 会忽略这些指令。更糟糕的是,你的一些代码甚至可以默默地调用错误的函数重载,因为你不再需要新的命名空间B
!
NOTE2 :在对问题的评论中,给出了Ideone示例。这很好地说明了名称空间中名称查找的细微之处:引用草案Standard, 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)Ni由X和中的using指令指定 它的内联命名空间集。
这解释了以下棘手的歧义
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头文件中单个声明的便利性。
答案 1 :(得分:1)
最好的方法是修复代码。
您可以分两步完成:
using ::B::X;