考虑一个模板化实体,比如(a(一个函数模板,(B(一个类模板的成员枚举。
// (A)
template<auto>
int f();
// (B)
template <auto>
struct T { enum class E; };
是否需要一个实现来诊断由于此类模板实体的相同显式专门化的重复定义而导致的ODR违规?或者,换句话说,[basic.def.odr]/1是否适用于显式专业化?
例如,GCC和Clang都将以下程序诊断为格式错误:
// Single translation unit;
// primary template of 'f' declared as in (A) above.
template<>
int f<0>() { return 0; }
template<>
int f<0>() { return 1; }
// GCC & Clang - error: redefinition of 'int f() [with auto <anonymous> = 0]'
而只有Clang将以下程序诊断为格式错误,而GCC接受它:
// Single translation unit;
// primary template of 'T' defined as in (B) above.
template<>
enum class T<0>::E { ex };
template<>
enum class T<0>::E { ey };
// Clang only - error: redefinition of 'E'
格式错误的NDR,还是格式错误的?(/两个编译器都正确,还是GCC错误?(
在-std=c++17
和-std=c++2a
的各种GCC和Clang版本上进行测试,结果相同
是否需要一个实现来诊断由于此类模板实体的相同显式专门化的重复定义而导致的ODR违规?
是。
尽管[temp.spec]/5.2指定程序中显式专门化的多个定义是格式错误的(同时引用[basic.def.odr](NDR(无需诊断(,但单个TU中的多个自定义属于[basic.def.odr]/1,例如,类模板的显式专业化(对于某些设置模板参数(是一个类。
任何翻译单元都不得包含任何变量、函数、类类型、枚举类型或模板的多个定义。
违反[basic.def.odr]/1不是NDR,并且实现应该对其进行诊断,GCC和Clang都会对违反odr的显式专门化(在同一TU内(进行诊断:
- 函数模板,以及
- 类模板,以及
- 变量模板,以及
- 类模板的成员函数,以及
- 类模板的静态数据成员,以及
- 类模板的成员类
然而,只有Clang将其诊断为类模板的成员枚举的显式专业化的TU本地ODR违规,这正是问题中使用的示例。
因此,成员枚举的这种未诊断的情况是GCC错误(作为本问题的一部分提交(:
- Bug 98120-类模板的成员枚举的显式专用化的多个定义(单个TU(