класс, использующий глобальную внешнюю переменную const, которая определяется с помощью внутренней связи
-
26-12-2019 - |
Вопрос
У меня такая ситуация:
// Test.h
extern const int param;
class Test
{
private:
int i;
public:
int foo();
};
и
// Test.cpp
#include "Test.h"
int Test::foo() { return param*10; }
и
// core.h
#include "Test.h"
const int param = 1; // should have internal linkage later in core.cpp
int do_stuff ();
и
// core.cpp
#include "core.h"
int do_stuff () { Test obj; return obj.foo(); }
int main() { return do_stuff(); }
Однако ошибки компоновщика нет.Как работает компоновщик см. Для Test.cpp в const int param
который осуществляется через core.h, определенный в core.cpp имеющий внутреннюю связь (по умолчанию для определений const)?
Когда я перепишу ядро.вот так (измените две строки):
// core.h
const int param = 1;
#include "Test.h"
int do_stuff ();
появляется ошибка компоновщика из-за отсутствия param
.А потом, когда я изменю это вот так:
// core.h
extern const int param = 1;
#include "Test.h"
int do_stuff ();
все снова работает.
Я подумал, что, возможно, в исходной ситуации есть автоматическая вставка класса Test внутри core.cpp, так что Test.cpp как бы не существует, а весь код находится в core.cpp, так что все работает.Но почему тогда это должно зависеть от изменения двух строк в core.h?
Решение
Ваше предположение о внутренней связи для определений const не всегда верно.Смотрите раздел "Стандарт" 3.5 Program linkage
, стр.3 (Я цитирую N3690):
Имя, имеющее область пространства имен (3.3.6), имеет внутреннюю связь, если это имя
переменная, функция или шаблон функции, который явно объявлен статическим;или,
энергонезависимая переменная, которая явно объявлена const или constexpr и ни extern, ни ранее было заявлено, что он имеет внешнюю связь;или
информационный член анонимного профсоюза.
Итак, для первого случая param
имеет внешнюю связь, и все в порядке.
Для второго случая существует внутренняя ссылка param
в core.cpp, но есть еще один заявленный-только param
имеющий внешнюю связь, но не имеющий определения.
В третьем случае есть один param
снова.