C++:链接命名空间内的外部变量

bre*_*ath 4 c++ linker namespaces constants extern

我似乎无法使用命名空间引用外部定义的变量extern.它在全局范围内工作,但只要在其中抛出命名空间,就无法链接.

我的常量文件看起来像:

StringConstants.cpp

#include "MyString.h"

MyString test1("string1");

MyString test2("string2");
Run Code Online (Sandbox Code Playgroud)

主程序如下所示:

main.cpp

#include <stdio.h>
#include "MyString.h"

extern MyString test1;

namespace {
    extern MyString test2;
}

int main(void) {
    printf("%s\n", test1.Str());
    printf("%s\n", test2.Str());
}
Run Code Online (Sandbox Code Playgroud)

我在GCC和Visual Studio中都遇到了类似的错误:

gcc    main.o StringConstants.o   -o main
main.o:main.cpp:(.text+0x49): undefined reference to `(anonymous namespace)::test2'
collect2: ld returned 1 exit status

1>Linking...
1>main.obj : error LNK2001: unresolved external symbol "class MyString `anonymous namespace'::test2" (?test2@?A0x0df4aa01@@3VMyString@@A)
1>C:\p4\namespace_repro\namespace_repro2\Debug\namespace_repro2.exe : fatal error LNK1120: 1 unresolved externals
Run Code Online (Sandbox Code Playgroud)

我尝试限定对test2(extern MyString ::test2)的引用,但它只是认为test2是MyString的静态成员.命名命名空间的行为与匿名命名空间的行为不同.由于各种原因,我们不希望删除命名空间或将外部函数放在命名空间之外.

这是其他文件,为了完整性:

MyString.h

class MyString {
public:
   MyString(const char* str): mStr(str) {};
   const char* Str() const { return mStr; }
private:
   const char* mStr; 
};
Run Code Online (Sandbox Code Playgroud)

Makefile

CC=gcc 
CFLAGS=-Wall

main: StringConstants.o main.o
Run Code Online (Sandbox Code Playgroud)

该系统的目标是所有常量都在一个文件中定义,并且它们在链接时解析而不是在标题中.似乎上面的代码可以工作,但由于它被两个不同的链接器拒绝,似乎我对C++的理解还不够好.有关如何使其工作的建议,除了将外部设置在命名空间之外?

Ton*_*roy 5

什么...

namespace { 
    extern MyString test2; 
} 
Run Code Online (Sandbox Code Playgroud)

...确实说test2应该存在于匿名命名空间中,但它不存在 - 它位于全局命名空间中.你已经骗了你的编译器,因此它生成了一个不会链接的对象.您需要从与变量相同的命名空间作用域生成extern声明.

但是,应该有一个StringConstants.h,main.cpp应该包含它,这样编译单元就可以知道字符串而不需要任何进一步的语句.


Chu*_*dad 5

$7.3.1/2 - “命名空间中首先声明的每个名称都是该命名空间的成员。”

这意味着名称“test2”是匿名命名空间的一部分,如果使用它,则应在该命名空间中定义。

这不仅仅是匿名名称空间的问题,而是任何名称空间的问题。