c++ - 代码重构后前向声明导致错误

标签 c++ namespaces refactoring forward-declaration using-directives

我原来的类结构类似于:

//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 的代码都应该重构以适应新的命名空间(这是一个解决方案),但不幸的是,这不是一个选择。

实际代码要复杂得多,这是一个简化的例子。

最佳答案

我意识到这更多的是关于新代码而不是重构现有代码,但我喜欢在这种情况下使用名为 X_fwd.hpp 的特殊 header 。

// 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:据我所知,使用 Peter Wood 对 typedef 的回答与您的 using 声明在技术上没有区别。请注意,using 指令 using namespace B; 可能会导致问题,因为它们会被 Argument-Dependent-Lookup 忽略。更糟糕的是,您的某些代码甚至可能会默默地调用错误的函数重载,因为您不再引入新的命名空间 B!

注意 2:在问题的评论中,Ideone给出了例子。这很好地说明了 namespace 内名称查找的微妙之处:引用草案 Standard , 3.4.3.2 命名空间成员 [namespace.qual] 部分,第 2 条

For a namespace X and name m, the namespace-qualified lookup set S(X, m) is defined as follows: Let S'(X, m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S'(X, m) is not empty, S(X, m) is S'(X, m); otherwise, S(X, m) is the union of S(Ni, m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

这解释了以下棘手的歧义

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!)
}

因此,在命名空间内同时具有同名的直接声明和使用声明的有效性是依赖于顺序的。因此,在 fwd 头文件中进行单个声明很方便。

关于c++ - 代码重构后前向声明导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14235780/

相关文章:

c++ - 在内联命名空间 header 中隐藏私有(private)常量

ios - 在 iOS 中重命名类

c++ - c++构造函数/typedef的扩展

c++ - SHA256 : Padding a 512 bits length message

c++ - 使用 Visual Studio 2010 是否需要 bscmake?

php - 如何检查尚未自动加载的类是否存在

java - 使用 jdk xpath 解析具有 namespace 的 xml 时出现问题

c++ - 在使用 boost 预处理器序列时避免扩展宏

refactoring - "Message Chains"与 "Middle Man"

design-patterns - 策略的替代模式