Ich weiß, dass Inline-Member-Funktionen per Definition in den Header aufgenommen werden sollten. Was aber, wenn es nicht möglich ist, die Implementierung der Funktion in den Header zu setzen? Nehmen wir diese Situation:
Datei Ah
#pragma once
#include "B.h"
class A{
B b;
};
Datei Bh
#pragma once
class A; //forward declaration
class B{
inline A getA();
};
Aufgrund des Rundschreibens muss ich die Umsetzung von getA
in setzen
B.cpp
#include "B.h"
#include "A.h"
inline A B::getA(){
return A();
}
Wird der Compiler inline getA
? Wenn ja, welches Inline-Schlüsselwort ist das signifikante (das im Header oder das in der CPP-Datei)? Gibt es eine andere Möglichkeit, die Definition einer Inline-Member-Funktion in die CPP-Datei aufzunehmen?
Antworten:
Zitieren aus C ++ FAQ :
Der Compiler muss die Definition der Inline-Funktion sehen, wenn er eine Verwendung dieser Inline-Funktion findet. Dies ist normalerweise möglich, wenn die Inline-Funktion in einer Header-Datei platziert wird.
Nein, außer wenn die Verwendung von
getA()
in B.cpp selbst erfolgt.Best Practice : nur in der Definition außerhalb des Klassenkörpers.
Nein, zumindest weiß ich es nicht.
quelle
Es kann nicht außerhalb des Anwendungsbereichs von B.cpp. Der Compiler arbeitet auf einer Basis pro Kompilierungseinheit, dh er kompiliert jede CPP-Datei einzeln. Wenn er also C. CPP kompiliert, ist der Code für getA () nicht verfügbar und er muss einen Funktionsaufruf und ausführen Lassen Sie den Linker das Problem beheben (oder, wenn er Sie wirklich beim Wort genommen und versucht hat, inline zu gehen, hat er einen Linkerfehler. Er
inline
hat ähnliche Eigenschaften wiestatic
).Die einzige Ausnahme ist LTCG, dh die Generierung von Link-Time-Code, die auf neueren Compilern verfügbar ist.
Ein Ansatz in diesem Fall besteht darin, eine andere Header-Datei (manchmal * .inl-Dateien genannt) zu haben, die den Inline-Code enthält.
BEARBEITEN: Welche Inline relevant ist - es ist die in der Klassendefinition, dh in der Header-Datei. Denken Sie daran, dass viele Compiler ihre eigenen Gedanken darüber haben, was eingebunden werden kann und sollte. gcc kann beispielsweise das Inlining vollständig deaktivieren (-O0) oder alles einbinden, was es für inlining hält (wie -O3).
quelle
-flto
wenn GCC und einige andere Compiler verwendet werden.Ich würde dies aus der entgegengesetzten Richtung tun.
Fügen Sie Ihrer Funktion keine Inline-Deklarationen hinzu (es sei denn, Sie benötigen dies auch).
Sie müssen die Inline-Deklaration nur dann zu einer Funktion / Methode hinzufügen, wenn Sie die Funktion in einer Header-Datei definieren, jedoch außerhalb der Klassendeklaration.
Xh
class X { public: int getX() { return 4;} // No inline because it is part of the class. // The compiler knows that needs an inline tag int getY(); int getZ(); }; inline int X::getY() { return 5;} // This needs to be explicitly declared inline. // Otherwise the linker will complain about // multiple definitions in compilation units.
X.cpp
// Never declare anything inline in the cpp file. int X::getZ() { return 6; }
Für Sie spezifischer Fall.
Entfernen Sie alle Inline-Spezifikationen. Sie tun nicht das, was Sie denken, dass sie tun.
quelle
Heutzutage können die meisten Compiler sowohl zur Verknüpfungszeit als auch zur Kompilierungszeit Inlining durchführen. Wenn Ihre Funktion wahrscheinlich vom Inlining profitiert, wird der Link Time-Optimierer wahrscheinlich genau das tun.
Bis der Linker darauf zugreift, ist nicht viel über den Inline-Status der Compilerausgabe verfügbar, außer dass der Compiler bestimmte Objekte als sammelbar kennzeichnet, beispielsweise weil eine Inline-Funktion oder eine Klassenvorlageninstanz in mehreren Kompilierungseinheiten angezeigt wird, oder Es sollte einen Fehler auslösen, wenn mehrere Symbole einen Namen gemeinsam haben, z. B. wenn die Hauptfunktion zweimal definiert wird. Nichts davon hat Einfluss auf den tatsächlichen Code, den es generiert.
quelle
Hier ist, wie ich es gemacht habe.
Datei Ah
#pragma once #include "B.h" class A { B b; };
Datei Bh
#pragma once class B { public: template<class T> inline T getA() { assert(NULL); // Use 'getA<A>()' template specialization only! return NULL; } }; class A; // Forward declaration template<> inline A B::getA<A>();
Datei Kap
#pragma once #include "A.h" #include "B.h" // Implement template specialization here! template<> inline A B::getA<A>() { return A(); }
Fügen Sie einfach die Datei "Ch" hinzu, um die Methode getA () verwenden zu können. Die einzige Änderung gegenüber dem ursprünglichen Code besteht darin, dass die Methode getA () als öffentlich statt als privat definiert werden muss.
Wie viele von Ihnen erklärt haben, ist dies jedoch nicht wirklich nützlich.
quelle
ISO / IEC 14882: 2014
quelle