2015-02-27 10 views
6

Si consideri il seguente codice:Una funzione inline in un file di intestazione può utilizzare una costante con collegamento interno?

const int a = 0; 
const std::string b = "hi"; 

inline void f_a1() 
{ 
    std::cout << a; 
} 

inline void f_b1() 
{ 
    std::cout << b; 
} 

inline void f_a2() 
{ 
    std::cout << &a; 
} 

inline void f_b2() 
{ 
    std::cout << &b; 
} 

Assumere esiste questo codice in un file di intestazione che sarà incluso in più unità di traduzione.

La mia comprensione delle funzioni inline è che devono essere esattamente uguali in ogni unità di traduzione.

La mia comprensione delle costanti come sopra utilizzata, è che sono implicitamente static cioè collegamento interno. Ciò significa che ciascuna unità di traduzione ottiene la propria copia.

Poiché le funzioni inline sopra si basano su queste costanti, quali di queste funzioni, se presenti, sono corrette?

+0

'f_a1' e' f_b1' sono corretti, perché si riferiscono al valore di una costante. Anche se il compilatore crea più di una costante, avranno tutti lo stesso valore. Quindi, anche se occorrenze diverse delle funzioni utilizzano costanti reali differenti, non infrangerà le aspettative per il codice (btw, la maggior parte del compilatore piegherà la costante 'int' direttamente nel codice generato, quindi non ci sarà un vero' a' costante nel tuo programma). Sto pensando agli altri due. –

+2

@GiulioFranco perché 'f_a2' pr' f_b2' non sarebbe corretto? –

+0

@LuchianGrigore Non ho detto che lo sono. Ci sto pensando.Se le costanti sono realmente collegate staticamente (cosa di cui non sono sicuro), il compilatore potrebbe avere diverse istanze di esse, che avranno indirizzi diversi, a meno che il linker non sia in grado di unificare le diverse definizioni (che dovrebbe essere il caso). –

risposta

6

Se incluso in più unità di traduzione, l'unica funzione valida è f_a1.

La clausola rilevante è [basic.def.odr]/6, che afferma che una funzione inline può apparire in più unità di traduzione, ma dato solo:

[...] un il nome può riferirsi a un oggetto non volatile const con collegamento interno o senza collegamento se l'oggetto ha lo stesso tipo letterale in tutte le definizioni di D, e l'oggetto è inizializzato con un'espressione costante (5.19) e l'oggetto non è odr -uso, e l'oggetto ha lo stesso valore in tutte le definizioni di D;

Poiché gli oggetti sono const, hanno il collegamento interno per [basic.link]/3:

Un nome avente namespace portata (3.3.6) ha il collegamento interno se è il nome di [...]
- una variabile non volatile che è esplicitamente dichiarata const o constexpr e né esplicitamente dichiarato extern né precedentemente dichiarato di avere collegamento esterno [...]

Tuttavia, prendendo l'indirizzo di o formando un riferimento a una variabile (ad es. per argomento passando) è odr-use, quindi f_a2 e f_b2 non sono validi. f_b1 non è valido, poiché l'operatore di output ostream per std::string prende il suo argomento per riferimento; e anche se ha preso il suo argomento in base al valore, il costruttore di copie implicitamente prende il suo argomento per riferimento. f_a1 è OK perché l'operatore dello stream-out int prende il suo argomento in base al valore e la copia del valore di uno int const non è in uso.

+3

Non sono sicuro che valga per "int const". –

+1

'f_a1' non * odr-usa * la costante' a', se sostituisci la costante con: 'struct T {const int a = 0; };/* nessuna definizione */'il codice dovrebbe comunque essere compilato come' std :: cout << T :: a' non * odr-use * 'T :: a' –

+1

3.2/2 * Una variabile il cui nome appare come un'espressione potenzialmente valutata è odr-used a meno che non sia un oggetto che soddisfa i requisiti per apparire in un'espressione costante (5.19) e la conversione lvalue-rvalue (4.1) viene applicata immediatamente *, poiché l'operatore utilizzato è: ' basic_ostream & operator << (int n); 'la conversione lvalue-rvalue viene applicata immediatamente e questo uso non è * odr-use * –

Problemi correlati