我有两个头文件,我包含在main.cpp中,在匿名命名空间中有以下定义:const string strToken = ("%");
使用g ++版本4.9进行编译会产生以下结果:
In file included from main.cpp:25:0:
libraries/trace.h:31:14: error: redefinition of ‘const string {anonymous}::strToken’
const string strToken = ("%");
^
In file included from libraries/debuglogger.h:12:0,
from libraries/packet.h:10,
from main.cpp:20:
libraries/strformat.h:23:14: note: ‘const string {anonymous}::strToken’ previously declared here
const string strToken = ("%");
^
我原以为在匿名命名空间中添加某些内容会将其限制在文件范围内,这使得这不是问题。我错过了什么,或者这是GCC中的某种缺陷?如果有人想要完整的代码我会愿意包含它,但我希望我在我的问题中包含了足够的信息以便不需要它。
答案 0 :(得分:3)
我原以为将某些内容放入匿名命名空间会将其限制为文件范围
你只是有点偏离。将内容放入匿名命名空间会限制它们对它们出现的翻译单元的可见性。翻译单元是变成单个目标文件的所有内容,通常是一个源文件(.cpp文件)以及来自该源文件中包含的头文件中的所有代码。所以,当你有main.cpp包含两个具有相同声明的头文件时(在匿名命名空间中),你会收到错误。
始终将#include
语句视为基本上只是标题内容的复制粘贴,而不是include语句。一旦你理解了这些问题,这些问题就会变得容易得多。例如,您的特定情况基本上归结为在解决了include语句后将此代码复制(复制粘贴到源文件中):
// from first header:
namespace {
const string strToken = ("%");
};
// from second header:
namespace {
const string strToken = ("%");
};
int main() { ... };
错误非常明显,并且匿名命名空间确实不会对基本问题进行任何更改,因为您对同一事物有多个定义。
匿名命名空间主要用于在翻译单元内部创建内容(通常在.cpp文件本身中),而不会在将翻译单元编译成目标文件后出现任何痕迹。您可能会发现this tutorial有助于理解整个编译和链接过程。
答案 1 :(得分:0)
我在做了一些研究后发现标题中的匿名命名空间是个坏主意。请参阅此处了解可能的解决方案:Hiding a C++ class in a header without using the unnamed namespace