[英]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
的同一类,但是前向声明会导致错误。 第二个问题是,我收到的错误消息没有指向正向声明的位置,并且查找/替换正向声明非常耗时。
现在,我已经解决了这个问题(困难的方式)。
处理这种情况的最佳方法是什么?
海事组织, using
在所有不应该在那里,所有的代码,使用X
需要重构,以适应新的命名空间(这是一个解决方案),但不幸的是,这是不是一种选择。
实际的代码要复杂得多,这是一个简化的示例。
我意识到这更多的是关于新代码,而不是重构现有代码,但是我喜欢在这种情况下使用称为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的typedef
答案和您的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中使用指令及其内联名称空间集提名的所有名称空间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头文件中使用单个声明的便利。
最好的方法是修复代码。
您可以分两个步骤进行操作:
using ::B::X;
删除using ::B::X;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.