Многократное определение решается с помощью шаблонов - PullRequest
0 голосов
/ 07 мая 2018

a.hpp:

#pragma once

struct S
{
  static int v;
};
int S::v = 0;

b.hpp:

#pragma once

void addOne();

b.cpp:

#include "b.hpp"
#include "a.hpp"

void addOne()
{
  S::v += 1;
}

main.cpp:

#include <iostream>

#include "a.hpp"
#include "b.hpp"

int main()
{
  S::v = 2;
  addOne();
  S::v += 2;
  std::cout << S::v << std::endl;
}

Не работает при компиляции с g++ -std=c++14 main.cpp b.cpp && ./a.out (множественное определение S :: v).

Однако, когда я изменяю код на: a.hpp:

#pragma once

struct S
{
  template<typename T>
  static int v;
};
template<typename T>
int S::v = 0;

и замените все S::v на S::v<void>, он компилируется и работает так, как я намеревался работать с первым примером (вывод 5).

Мне кажется, я знаю, почему не работает первый пример кода: строка int S::v = 0; однажды скомпилируется в модуле main.cpp и один раз в модуле b.cpp. Когда компоновщик связывает эти два элемента вместе, переменная S::v по существу переопределяется. (?)

Почему работает код с шаблоном?

1 Ответ

0 голосов
/ 07 мая 2018

Почему работает код с шаблоном?

По сути, потому что в стандарте так сказано.

С шаблонами правила обычно сводятся к следующему: «каждый используету них должно быть свое определение ".То же самое относится и к статическим членам данных шаблонов классов: определение такого статического члена данных должно присутствовать в каждой единице перевода, в которой он используется odr.Компилятор и компоновщик должны убедиться, что это не приведет к ошибкам.

Обратите внимание, что начиная с C ++ 17, вы можете решить случай, не связанный с шаблоном, сделав статический член данных встроенным:

#pragma once

struct S
{
  static inline int v = 0;
};
...