classe usando variável const externa global que é definida com ligação interna
-
26-12-2019 - |
Pergunta
Eu tenho esta situação:
// Test.h
extern const int param;
class Test
{
private:
int i;
public:
int foo();
};
e
// Test.cpp
#include "Test.h"
int Test::foo() { return param*10; }
e
// core.h
#include "Test.h"
const int param = 1; // should have internal linkage later in core.cpp
int do_stuff ();
e
// core.cpp
#include "core.h"
int do_stuff () { Test obj; return obj.foo(); }
int main() { return do_stuff(); }
No entanto, não há erro de vinculador.Como o vinculador vê para Test.cpp o const int param
que é através de core.h definido em core.cpp com ligação interna (padrão para definições const)?
Quando reescrevo core.h assim (mude duas linhas):
// core.h
const int param = 1;
#include "Test.h"
int do_stuff ();
ocorre um erro de vinculador por falta param
.E então, quando eu mudo assim:
// core.h
extern const int param = 1;
#include "Test.h"
int do_stuff ();
tudo funciona novamente.
Pensei que talvez na situação original exista um inlining automático da classe Test dentro de core.cpp, para que Test.cpp seja inexistente e todo o código esteja em core.cpp, para que tudo funcione.Mas por que deveria depender da alteração das duas linhas em core.h?
Solução
Sua suposição sobre a ligação interna para definições const nem sempre é verdadeira.Veja a seção padrão 3.5 Program linkage
, pág.3 (estou citando N3690):
Um nome com escopo de namespace (3.3.6) possui ligação interna se for o nome de
uma variável, função ou modelo de função que é explicitamente declarado como estático;ou,
uma variável não volátil que é explicitamente declarada const ou constexpr e nem declarada explicitamente extern nem anteriormente declarado ter ligação externa;ou
um membro de dados de uma união anônima.
Então, para o primeiro caso param
tem ligação externa e está tudo bem.
Para o segundo caso, existe um link interno param
em core.cpp, mas há outro somente declarado param
tendo ligação externa, mas sem definição.
No terceiro caso, há um param
de novo.