2015-02-27 14 views
6

Betrachten Sie den folgenden Code ein:Kann eine Inline-Funktion in einer Header-Datei eine Konstante verwenden, die intern verknüpft ist?

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; 
} 

Angenommen, dieser Code in einer Header-Datei vorhanden ist, die in mehreren Übersetzungseinheiten aufgenommen werden.

Mein Verständnis von Inline-Funktionen ist, dass sie in jeder Übersetzungseinheit genau gleich sein müssen.

Mein Verständnis von Konstanten, wie oben verwendet, ist, dass sie implizit sind static dh interne Verknüpfung. Dies bedeutet, dass jede Übersetzungseinheit ihre eigene Kopie erhält.

Da die obigen Inline-Funktionen auf diesen Konstanten beruhen, welche dieser Funktionen sind, wenn überhaupt, korrekt?

+0

'f_a1' und' f_b1' sind korrekt, da sie sich auf den Wert einer Konstanten beziehen. Selbst wenn der Compiler mehr als eine Konstante erstellt, haben sie alle den gleichen Wert. Selbst wenn unterschiedliche Vorkommen der Funktionen unterschiedliche tatsächliche Konstanten verwenden, wird es die Erwartungen für den Code nicht brechen (übrigens wird der meiste Compiler die Konstante "int" direkt in dem erzeugten Code falten, so dass es kein tatsächliches "a" gibt Konstante in Ihrem Programm). Ich denke an die anderen beiden. –

+2

@GiulioFranco Warum wäre 'f_a2' pr' f_b2' falsch? –

+0

@LuchianGrigore Ich habe nicht gesagt, dass sie es sind. Ich denke darüber nach.Wenn die Konstanten wirklich statisch verknüpft sind (worüber ich nicht sicher bin), dann könnte der Compiler unterschiedliche Instanzen von ihnen haben, die unterschiedliche Adressen haben, wenn der Linker nicht in der Lage ist, die verschiedenen Definitionen zu vereinheitlichen (was der Fall sein sollte)). –

Antwort

6

Wenn in mehrere Übersetzungseinheiten eingeschlossen, ist die einzige gültige Funktion f_a1.

Die entsprechende Klausel ist [basic.def.odr]/6, die eine inline Funktion stellt fest, dass in mehreren Übersetzungseinheiten erscheinen kann, aber nur da:

[...] ein Der Name kann sich auf ein nichtflüchtiges const Objekt mit interner oder keiner Verknüpfung beziehen, wenn das Objekt in allen Definitionen von D, denselben Literaltyp hat und das Objekt mit einem konstanten Ausdruck (5.19) initialisiert wird und das Objekt nicht odr ist -used, und das Objekt hat in allen Definitionen von D den gleichen Wert;

Da die Objekte sind const, haben sie interne Bindung pro [basic.link]/3:

Ein Name mit Namespacebereich (3.3.6) interne Bindung hat, wenn es das ist, Namen [...]
- eine nichtflüchtige variablen, die explizit const oder constexpr deklariert wird und weder explizit extern erklärt noch vorher externe Bindung erklärt haben [...]

Aber die Adresse zu nehmen oder einen Bezug zu einer Variablen zu bilden (z.B. für Argument übergeben) ist odr-use, so f_a2 und f_b2 sind ungültig. f_b1 ist auch ungültig, da der ostream Ausgabeoperator für std::string sein Argument durch Verweis nimmt; und selbst wenn es sein Argument nach Wert nahm, würde der implizit als Copy-Konstruktor bezeichnete Code sein Argument als Referenz nehmen. f_a1 ist in Ordnung, weil der int Stromausgabebediener sein Argument nach Wert nimmt, und das Kopieren des Werts eines int const ist nicht odr-use.

+3

Ich bin mir nicht sicher, dass das für 'int const' gilt. –

+1

'f_a1' verwendet * odr-use * die 'a'-Konstante nicht, wenn Sie die Konstante ersetzen durch:' struct T {const int a = 0; };/* no definition */'der Code sollte immer noch gut kompilieren als' std :: cout << T :: a 'nicht * odr-use * 'T :: a' –

+1

3.2/2 * Eine Variable, deren Name als erscheint Ein potenziell ausgewerteter Ausdruck wird odr-verwendet, es sei denn, es ist ein Objekt, das die Anforderungen für das Erscheinen in einem konstanten Ausdruck erfüllt (5.19) und die lvalue-to-rvalue-Umwandlung (4.1) wird sofort angewendet *, da der verwendete Operator: ' basic_ostream & Operator << (int n); 'die lvalue-to-rvalue-Konvertierung wird sofort angewendet und diese Verwendung ist nicht * odr-Verwendung * –