classe utilizzando la variabile const esterna globale definita con collegamento interno
-
26-12-2019 - |
Domanda
Ho questa situazione:
// 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(); }
Tuttavia non è presente alcun errore del linker.In che modo il linker vede per Test.cpp il file const int param
che è tramite core.h definito in core.cpp con collegamento interno (impostazione predefinita per le definizioni const)?
Quando riscrivo core.h in questo modo (cambia due righe):
// core.h
const int param = 1;
#include "Test.h"
int do_stuff ();
si verifica un errore del linker per mancanza param
.E poi, quando lo cambio in questo modo:
// core.h
extern const int param = 1;
#include "Test.h"
int do_stuff ();
tutto funziona di nuovo.
Ho pensato che forse nella situazione originale c'è un incorporamento automatico della classe Test all'interno di core.cpp, in modo che Test.cpp sia inesistente e l'intero codice sia in core.cpp, quindi tutto funziona.Ma perché dovrebbe dipendere dalla modifica delle due righe in core.h?
Soluzione
La tua ipotesi sul collegamento interno per le definizioni const non è sempre vera.Vedi la sezione standard 3.5 Program linkage
, P.3 (sto citando N3690):
Un nome con ambito namespace (3.3.6) ha un collegamento interno se è il nome di
una variabile, funzione o modello di funzione esplicitamente dichiarato statico;O,
una variabile non volatile dichiarata esplicitamente const o constexpr e non dichiarata esplicitamente né extern né precedentemente dichiarato di avere un collegamento esterno;O
un membro dei dati di un'unione anonima.
Quindi per il primo caso param
ha un collegamento esterno e va tutto bene.
Per il secondo caso, esiste un collegamento interno param
in core.cpp, ma ce n'è un altro solo dichiarato param
con collegamento esterno ma senza definizione.
Nel terzo caso ce n'è uno param
Ancora.