Определение шаблона * stati c зависит от порядка, переданного компоновщику - PullRequest
4 голосов
/ 15 апреля 2020

Следующий код, который имеет 2 определения для элемента поля stati c, каждое определение определяет template1<int>::x с другим значением.

Можно ожидать, что компоновщик отклонит такие переопределения, поскольку они имеют разные значения.

Но компиляция и компоновка проходят как для g ++, так и для MSV C, и то, какое определение используется, зависит от порядка, в котором источники передаются компоновщику.

Is это поведение соответствует стандарту C ++, неопределенное поведение или ошибка компоновщика?

my_template.h

template <class T>
class template1
{
public:
    static int x;
};

Src2. cpp

#include <stdio.h>
#include "my_template.h"

template <class T>
int template1<T>::x = 2; 

void my_func() // definition
{
    printf("my_func: template1<int>::x = %d\n", template1<int>::x); // definition of X to 2.
    printf("my_func: template1<char>::x = %d\n", template1<char>::x); // definition of X to 2.
}

Main. cpp

#include <cstdio>
#include "my_template.h"

template <class T>
int template1<T>::x = 1;

void my_func();

int main()
{
    printf("main: template1<int>::x = %d\n", template1<int>::x); // definition of X to 1.
    my_func();
    return 0;
}

Скомпилировать с g ++ (MinGW.org G CC Build-20200227-1) 9.2.0 +

Compile1

g++ -o prog Src2.cpp Main.cpp

Output1

main: template1<int>::x = 2
my_func: template1<int>::x = 2
my_func: template1<char>::x = 2

Compile2

g++ -o prog Main.cpp Src2.cpp

Ouput2

main: template1<int>::x = 1
my_func: template1<int>::x = 1
my_func: template1<char>::x = 2

Наблюдается также с

Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28612 for x86

Когда я разбирал код с флагом -S, каждая единица компиляции d определено то же имя символа.

Совместная работа с Nightra .

Ответы [ 2 ]

5 голосов
/ 15 апреля 2020

Это нарушает ODR (что требует, чтобы у сущности было точно одно определение, если оно используется). Таким образом, программа имеет UB.

Компилятор не может диагностировать это, потому что с каждой единицей перевода все в порядке. Теоретически, компоновщик может диагностировать это, но на практике он этого не сделает.

2 голосов
/ 15 апреля 2020

Соответствует ли это поведение стандарту C ++, неопределенному поведению или ошибке компоновщика?

Это неопределенное поведение (UB).


От [basi c .def.odr] / 4 из N4659 [ выделение mine]:

Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе с помощью odr вне исключенного оператора; без диагностики c требуется . Определение может явным образом появиться в программе, оно может быть найдено в стандартной или пользовательской библиотеке, или (при необходимости) оно неявно определено (см. [Class.ctor], [class.dtor] и [class.copy). ]). Встроенная функция или переменная должна быть определена в каждой единице перевода, в которой она используется odr, вне отброшенного оператора.

Не constexpr static переменные-члены шаблонов равны не неявно inline, и, следовательно, это UB, диагностика не требуется c не требуется.

Мы также можем обратиться к [basi c .def.odr] / 6 для еще более сильного утверждения (даже не требующего использования ODR) [цитируя выбранный фрагмент, выделение мое]:

Может быть более одного определения [. ..] stati c член данных шаблона класса [...] в программе при условии, что каждое определение появляется в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям . Если такой объект с именем D определен более чем в одной единице перевода, то

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

[...]

Если определения D удовлетворяют всем этим требованиям, , тогда поведение такое, как если бы было одно определение D. Если определения D не удовлетворяют этим требованиям, , тогда поведение не определено .

С двумя различными определениями D (в в вашем случае template1<int>::x) «каждое определение D должно состоять из одной и той же последовательности токенов» не выполняется, и из этого следует, что мы, естественно, не можем выполнить »[... ] как если бы было одно определение D "; таким образом UB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...