#c #templates #language-lawyer #template-specialization #one-definition-rule
#c #шаблоны #язык-юрист #шаблон-специализация #правило одного определения
Вопрос:
Рассмотрим шаблонную сущность, скажем, (А) шаблон функции и (Б) перечисление элементов шаблона класса.
// (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 amp; 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?)
Протестировано на различных версиях GCC и Clang, для -std=c 17
и -std=c 2a
, с тем же результатом
Ответ №1:
Требуется ли реализация для диагностики нарушений 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 (поданной как часть этого вопроса):