Как шаблон влияет на привязку глобальной переменной const?

Как говорится в документе (выделено мной):

Любое из следующих имен, объявленных в области пространства имен, имеет внутреннюю связь:

  • энергонезависимые не шаблонные неинлайновые переменные с указанием константы (включая constexpr), которые не объявлены extern и ранее не объявлены как имеющие внешнюю связь;

Поэтому я ожидаю, что константные переменные шаблона будут иметь внешнюю связь. Итак, я провел тест:

// main.cpp
void other();

template<class T> T var = 1;
template<class T> const T constVar = 1;

int main() {
  std::cout << var<int> << ' ' << constVar<int> << std::endl;
  other();
}

// other.cpp
template<class T> T var = 2;
template<class T> const T constVar = 2;

void other() {
  std::cout << var<int> << ' ' << constVar<int> << std::endl;
}

И вывод:

1 1
1 2

Второй столбец для constVar, и он разный для разных строк (печатается из разных единиц перевода). Это заставляет меня думать, что на самом деле у него есть внутренняя связь, несмотря на то, что это шаблон.

Я понимаю, что нарушаю ODR, но только для того, чтобы понять, что происходит.

Так действительно ли constVar имеет внутреннюю связь? Если да, то что означает выделенный фрагмент документа? Если нет, то что происходит и зачем нам этот выделенный фрагмент?


person Mikhail    schedule 29.10.2019    source источник
comment
Они оба являются шаблонами, поэтому абзац просто не применяется?   -  person Aconcagua    schedule 29.10.2019
comment
Это больше похоже на нарушение ODR (т.е. UB), чем на привязку. Но я ничего не знаю о переменных шаблона, так что это может быть неправильно.   -  person Max Langhof    schedule 29.10.2019
comment
@Aconcagua точно, но поведение похоже на то, что constVar имеет внутреннюю связь, то есть абзац кажется примененным   -  person Mikhail    schedule 29.10.2019
comment
@Mikhail Нет, похоже, что компилятор константно сворачивает (предположительно) постоянное значение в вывод. Вы нарушаете одно правило определения, поэтому вы получаете неопределенное поведение.   -  person Max Langhof    schedule 29.10.2019
comment
@MaxLanghof хорошо, это разумное объяснение. Однако мне интересно, что означает переменная, не являющаяся шаблоном. Нет такой вещи, как переменная шаблона, есть только шаблон переменной. Мы можем использовать и то, и другое, но стандарт остерегается этого. eel.is/c++draft/basic.link#5.2 говорит без шаблона, а затем eel.is/c++draft/basic.link# 6.5 снова исключает шаблоны. Странный.   -  person Mikhail    schedule 29.10.2019
comment
Из связанных вопросов: stackoverflow. ком/вопросы/46335920/   -  person Max Langhof    schedule 29.10.2019
comment
Попробуйте также распечатать &constVar<int>.   -  person aschepler    schedule 30.10.2019


Ответы (1)


C++14 N4296 §14.4

Имя шаблона имеет связь (3.5). [...] Определения шаблонов должны подчиняться правилу одного определения (3.2).

C++14 N4296 §3.2.6< /а>

Учитывая такой объект с именем D, определенный более чем в одной единице перевода, тогда

  • каждое определение D должно состоять из одной и той же последовательности токенов; [...]

Если D является шаблоном и определен более чем в одной единице перевода, то предыдущие требования должны применяться как к именам из объемлющей области шаблона, используемой в определении шаблона (14.6.3), так и к зависимым именам в точке инстанцирования. (14.6.2). Если определения D удовлетворяют всем этим требованиям, то поведение будет таким, как если бы существовало одно определение D. Если определения D не удовлетворяют этим требованиям, то поведение не определено.

Шаблоны неявно встроены, т.е. имеют внешнюю связь. Что происходит = неопределенное поведение. Компилятор не обязан диагностировать ваш код и может давать неожиданные/несогласованные результаты.

person Baptistou    schedule 29.10.2019
comment
Из вопроса: я понимаю, что нарушаю ODR, но только для того, чтобы понять, что происходит. - person Mikhail; 29.10.2019
comment
Вопрос о привязке. Если шаблон имеет внутреннюю связь, то определяются два разных шаблона, а не шаблон, определенный более чем в одной единице перевода, поэтому ODR не применяется. - person aschepler; 30.10.2019