2010-11-18 74 views
4

我似乎无法使用extern从命名空间内引用外部定义的变量。它从全局范围起作用,但是一旦命名空间被抛出,它就无法链接。C++:链接命名空间内的外部变量

我的常量文件看起来像:

StringConstants.cpp

#include "MyString.h" 

MyString test1("string1"); 

MyString test2("string2"); 

主要程序是这样的:

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()); 
} 

我得到了GCC和视觉类似的错误工作室:

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" ([email protected][email protected]@[email protected]@A) 
1>C:\p4\namespace_repro\namespace_repro2\Debug\namespace_repro2.exe : fatal error LNK1120: 1 unresolved externals 

我试着限定引用test2(extern MyString ::test2),但它只是认为test2是MyString的静态成员。命名命名空间的行为与匿名行为不同。由于各种原因,我们不想删除名称空间或将名字空间外的extern。

这里的其他文件,完整性:

MyString.h

class MyString { 
public: 
    MyString(const char* str): mStr(str) {}; 
    const char* Str() const { return mStr; } 
private: 
    const char* mStr; 
}; 

Makefile

CC=gcc 
CFLAGS=-Wall 

main: StringConstants.o main.o 

该系统的目标是常量都在同一个文件中定义,并他们会在链接时解决,而不是在标题中。看起来好像上面的代码可以工作,但是由于它被两个不同的连接器拒绝,看来我对C++的理解还不够好。除了将外部名称放在命名空间之外,还有关于如何实现这一功能的建议?

回答

4

$ 7.3.1/2 - “每一个名字第一次宣布 的命名空间是 命名空间中的一员。”

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

单独使用匿名命名空间并不是一个问题,但对于这个问题,任何命名空间都不是问题。

+0

*叹*我想我不能不同意这个规范,我多次看过那个部分, t解析该特定行的含义,谢谢拼写。 – breath 2010-11-18 03:17:30

5

什么...

namespace { 
    extern MyString test2; 
} 

...确实是说test2的应在一个匿名的命名空间存在,但它没有 - 它是在全局命名空间。你欺骗了你的编译器,因此它会生成一个不会链接的对象。您需要使用与变量相同的命名空间作用域来创建extern声明。

但是,应该有一个StringConstants.h,main.cpp应该包含这些信息,以便编译单元不需要任何进一步的语句即可知道字符串。

+0

+1,匿名命名空间是这里的罪魁祸首。请注意,他仍然需要使用extern,无论它是否在标题中。 – avakar 2010-11-18 01:36:56

+0

有一个StringConstants.h的问题是,当有人修改或添加一个常量(这很常见)时,它基本上需要重新编译程序中的每个文件。有什么办法可以告诉编译器我想引用全局test2吗? – breath 2010-11-18 02:09:10

+0

@breath:如果事情不稳定,没有共享头文件会更糟糕:当某人发现某些值时应该将int从int更改为double?程序在运行时不断建立和链接并失败。如果共享报头真的太难了,那么可以考虑将它分成单独的报头,用于减少翻译单元所需的易失部分。考虑pImpl,接口和其他抽象,帮助解耦客户端与实现。 – 2010-11-18 02:20:56