不同模块中的ambigous结构定义

时间:2017-10-29 11:04:13

标签: c++ visual-studio c++11 struct compiler-bug

我有一个带有MS Visual Studio 2015的大型C ++ 11项目,它在两个模块(=编译单元,cpp文件)中定义了两个具有相同名称但内容不同的结构。由于stucts仅在模块中定义和使用,而不是通过任何头文件导出以供共享使用,因此应该允许这样,实际上编译器和链接器都不会报告任何错误或警告。但是在运行时,我从包含结构的无序映射的构造函数中获取访问冲突。 Visual Studio 2017也会出现此问题,但不适用于gcc5.4。在我看来这是一个编译器错误,但我不是很确定。 下面是一些重现问题的最小化源代码,只需链接任何可执行文件,以便在main()之前启动时获取访问冲突。

module1.cpp:

#include <unordered_map>
struct AmbigousStruct {
    int i1;
    int i2;
    int i3;
};
static const std::unordered_map<int, AmbigousStruct>
s_ambigousStructMap{
    { 0, { 0, 1, 2 } }
};

module2.cpp:

#include <unordered_map>
struct AmbigousStruct {
    int i1;
    int i2;
};
static const std::unordered_map<int, AmbigousStruct>
s_ambigousStructMap{
    { 0, { 0, 1 } }
};

问题似乎与在模板类中使用struct(在本例中为unordered_map)有关,因为它不会出现在struct的简单实例中,即module2.cpp:

static const AmbigousStruct s_ambigousStructInstance{ 0, 1 };

2 个答案:

答案 0 :(得分:1)

您有两种具有外部链接的类类型,具有相同的名称,以不同的翻译单位定义。他们的成员不匹配,并且违反了One Definition Rule。您的程序格式错误,无需诊断。

您需要强制该结构定义上的内部链接。 C ++标准允许您使用匿名命名空间执行此操作。实际上,匿名命名空间使中的所有具有内部链接。因此,您不需要static修饰符来处理其他事情:

namespace {
  struct AmbigousStruct {
    int i1;
    int i2;
  };
  const std::unordered_map<int, AmbigousStruct>
  s_ambigousStructMap {
    { 0, { 0, 1 } }
  };
}

答案 1 :(得分:0)

这是一个链接器问题,而不是编译器错误。链接器将采用找到的第一个定义并忽略第二个定义。

要解决此问题,请使用未命名的命名空间,以用于仅在翻译单元中本地使用的任何内容:

namespace { // Everything contained is only visible in the current 
            // translation unit
    struct AmbigousStruct {
        int i1;
        int i2;
        int i3;
    };
    const std::unordered_map<int, AmbigousStruct> s_ambigousStructMap {
        { 0, { 0, 1, 2 } }
    };
}

在另一个.cpp文件中也是如此。