首页 > 解决方案 > Linux 上的 GCC 在错误的命名空间中搜索前向声明的方法

问题描述

考虑以下场景:

源码.cpp

int add(int a, int b) { return a + b; } // function in global scope

头文件.h

namespace ns
{
    class A
    {
    public:
        void do()
        {
            ...
            ...
            method();
            ...
            ...
        }
    private:
        int method()
        {
            ...
            ...
            int add(int a, int b); // forward declaration
            auto result = add(5, 10); // function call
            ...
            ...
            // do something with result
        }
    };
}

Windows (MS Compiler)上,上述工作按预期工作。

Linux (GCC)上,它会导致链接器错误,其中该方法add()被报告为未定义的引用

更重要的是,错误表明编译器试图add()在命名空间下查找ns,但它在全局命名空间中明确定义。

在链接前向声明的方法时,Linux 上的 GCC 的行为是否与 Windows 上的 MS 编译器不同?我该如何解决这个问题?

标签: c++11gcclinkerforward-declaration

解决方案


MS 编译器的名称查找不符合 C++11 标准,将 的声明int add(int a, int b)解析ns::A::methodSource.cpp. 该声明在命名空间内 ,它应该声明ns的函数是GCC(或 clang)抱怨的,没有定义。int ns::add(int a, int b)

C++11 § 3.5 第 7 段:

如果没有发现具有链接的实体的块范围声明引用其他声明,则该实体是最内层封闭命名空间的成员。然而,这样的声明并没有在其命名空间范围内引入成员名称。[ 例子:

namespace X {
    void p() {
        q(); // error: q not yet declared
        extern void q(); // q is a member of namespace X
    }
    ...
    ...

    void q() { /* ... */ } // definition of X::q
}

void q() { /* ... */ } // some other, unrelated q

结束示例]

您有两种选择:-

  • int add(int a, int b)将out of namespace 的前向声明提升ns到全局命名空间 - 它在其中定义的地方source.cpp

  • 附上命名空间中的int add(int a, int b)定义ns

源.cpp

namespace ns {
    int add(int a, int b) { return a + b; }
}

推荐阅读