提问人:Luchian Grigore 提问时间:1/9/2013 最后编辑:TemplateRexLuchian Grigore 更新时间:1/10/2013 访问量:331
代码重构后,正向声明会导致错误
Forward declarations cause errors after code refactor
问:
我原来的类结构类似于:
//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
实际代码要复杂得多,这是一个简化的示例。
答:
最好的方法是修复代码。
您可以通过两个步骤完成:
- 修复所有正向声明
- 删除
using ::B::X;
评论
using
我意识到这更多的是关于新代码,而不是重构现有代码,但我喜欢使用在这种情况下调用的特殊标头。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...)。
注1:AFAIK,使用Peter Wood的答案和你的声明之间没有技术上的区别。请注意,指令可能会导致麻烦,因为 Argument-Dependent-Lookup 会忽略这些指令。更糟糕的是,你的一些代码甚至可能以静默方式调用错误的函数重载,因为你不再拉取新的命名空间了!typedef
using
using
using namespace B;
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) 表示所有命名空间 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 头文件中使用单个声明非常方便。
评论
上一个:Java 语法问题
下一个:在 C++ 中返回时触发事件
评论
fwd.h
def_fwd.h
iosfwd
X
B
namespace A
B
A