是否需要一个实现来诊断同一 TU 内同一显式专业化的重复定义的 ODR 违规?

dfr*_*fri 9 c++ templates one-definition-rule template-specialization language-lawyer

考虑一个模板化实体,比如说(A)一个函数模板,和(B)一个类模板的成员枚举。

// (A)
template<auto>
int f();

// (B)
template <auto>
struct T { enum class E; };
Run Code Online (Sandbox Code Playgroud)

由于此类模板实体的相同显式专业化的重复定义,是否需要实现来诊断 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]'
Run Code Online (Sandbox Code Playgroud)

而只有 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'
Run Code Online (Sandbox Code Playgroud)

格式错误的 NDR,还是格式错误的?(/两个编译器都正确,还是 GCC 错误?)


在各种 GCC 和 Clang 版本上进行测试,对于-std=c++17-std=c++2a,结果相同

dfr*_*fri 3

由于此类模板实体的相同显式专业化的重复定义,是否需要实施来诊断 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 错误(作为此问题的一部分提交):