如何强制c++链接器捕获枚举定义的冲突?



我有这两个源文件,编译和链接没有任何问题。

a.cpp

enum class numbers
{
one,
two,
};
const char* getName(numbers number)
{
switch (number)
{
case numbers::one:
return "one";
break;
case numbers::two:
return "two";
break;
}
}

b.cpp

#include <iostream>
enum class numbers
{
zero,
one,
two,
};
const char* getName(numbers number);
void print(numbers number)
{
std::cout << getName(number);
}
int main()
{
print(numbers::one);
return 0;
}

可以看到,相同的enum类在每个文件中定义不同。我正在寻找一种在不同的翻译单元中捕获枚举类的这种冲突(在我们非常非常大的代码库中导致错误)的方法。是否任何编译器/链接器有能力在这种情况下产生错误?

显示的错误违反了一个定义规则。

c++标准不要求编译器或链接器在违反单一定义规则时报告诊断。即"不需要诊断"。

换句话说:你的c++编译器不需要报告这个特定的错误。这是因为在许多情况下,由于在某些特定的操作系统或平台上如何编译和链接代码的低级技术实现细节,从技术上检测对一个定义规则的违反是不可能的。

一般来说:报告尽可能多的有用的诊断是每个现代c++编译器的兴趣所在。换句话说:如果c++编译器有可能检测到ODR违反,它将很容易这样做,而不需要强制执行。如果您的c++编译器没有生成ODR违规的诊断,则不太可能有任何隐藏的开关或按钮可以按下以使错误出现。

链接器不可能捕捉到这个。枚举类定义只定义编译器将用于生成代码的一些编译时常量。没有为枚举的任何标识符创建对象,以便链接器可以看到并警告重复项。

我也不明白为什么这段代码会是一个问题。您没有导出类型,它仅在编译单元中使用。这两个定义之间没有交叉。虽然标准可能指向一个定义规则,但我认为没有实际问题。

但是如果你试图制造一个问题,如果你把类型放入头文件中,并试图包括这两个,那么编译器将会失败,因为一个重复的定义。任何从a.p和b.p调用getname()或使用枚举的尝试都将包含a.h和b.h,然后失败。所以,除非你在写头文件的时候很粗心,并且在没有定义的情况下使用前向声明,否则你总是会在重要的时候得到一个错误。