web-dev-qa-db-de.com

C++ - Inline-Member-Funktion in der .cpp-Datei

Ich weiß, dass Inline-Member-Funktionen per Definition in die Kopfzeile aufgenommen werden sollten. Was aber, wenn die Implementierung der Funktion nicht in den Header eingefügt werden kann? Nehmen wir diese Situation an:

Datei A.h

#pragma once
#include "B.h"

class A{
    B b;
};

Datei B.h

#pragma once

class A; //forward declaration

class B{
    inline A getA();
};

Aufgrund des Rundschreibens muss ich die Implementierung von getA einfügen

B. cpp

#include "B.h"
#include "A.h"

inline A B::getA(){
    return A();
}

Wird der Compiler inline getA sein? 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 ihre .cpp-Datei zu übernehmen?

62
Mat

Zitieren aus C++ FAQ :

Hinweis: Es ist zwingend, dass die Funktionsdefinition (der Teil zwischen den {...}) wird in ein .__ eingefügt. Header-Datei, es sei denn, die Funktion ist Wird nur in einer einzelnen .cpp-Datei verwendet. Im Insbesondere wenn Sie die Inline .__ setzen. Funktionsdefinition in eine CPP-Datei und Sie nennen es von einem anderen .cpp Datei erhalten Sie vom Linker eine Fehlermeldung "nicht gelöst extern".

Der Compiler muss die definition der Inline-Funktion sehen, wenn er diese Inline-Funktion verwendet. Dies ist normalerweise möglich, wenn die Inline-Funktion in einer Header-Datei platziert wird.

Wird der Compiler Inline getA? 

Nein, außer wenn die Verwendung von getA() in B.cpp selbst erfolgt.

Wenn ja, welches Inline-Schlüsselwort ist das signifikante (das im Header oder das im cpp)?

Best Practice : nur in der Definition außerhalb des Klassenkörpers.

Gibt es eine andere Möglichkeit, die Definition einer Inline-Member-Funktion in ihre cpp-Datei zu übernehmen?

Nein, zumindest weiß ich es nicht.

63
Arun

Es kann nicht außerhalb des Geltungsbereichs von B.cpp liegen. Der Compiler arbeitet auf einer Basis pro kompilierter Einheit, dh er kompiliert jede .cpp-Datei einzeln. Wenn er also ccpp kompiliert, steht ihm nicht der Code für getA () zur Verfügung und er muss einen Funktionsaufruf ausführen Lassen Sie den Linker das Problem beheben (oder wenn Sie wirklich durch das Wort gedrängt und versucht haben, Inline zu integrieren, wird am Ende ein Linker-Fehler ausgegeben. inline hat ähnliche Eigenschaften wie static).

Die einzige Ausnahme ist LTCG, d. H. Link-Time-Code-Generierung, die auf neueren Compilern verfügbar ist.

Ein Ansatz in diesem Fall besteht darin, eine andere Header-Datei (manchmal * .inl-Dateien) zu haben, die den eingebetteten Code enthält.

BEARBEITEN: Was für Inline relevant ist, ist dies in der Klassendefinition, d. H. In der Header-Datei. Denken Sie daran, dass viele Compiler eine eigene Meinung dazu haben, was inline dargestellt werden kann und soll. gcc zum Beispiel kann das Inlining vollständig deaktivieren (-O0) oder alles, was es als wertvoll erachtet, (wie -O3).

16
EboMike

Ich würde das aus der entgegengesetzten Richtung machen.

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 einer Funktion/Methode hinzufügen, wenn Sie die Funktion in einer Header-Datei definieren, jedoch außerhalb der Klassendeklaration.

X.h

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 genauer Fall.
Entfernen Sie alle Inline-Spezifikationen. Sie tun nicht das, was Sie denken.

9
Martin York

Heutzutage können die meisten Compiler sowohl zur Linkzeit als auch zur Kompilierzeit Inlining ausführen. Wenn Ihre Funktion wahrscheinlich vom Inlining profitieren wird, dann wird der Link Time-Optimizer wahrscheinlich genau das tun.

Zu dem Zeitpunkt, zu dem der Linker ankommt, ist nicht viel über den Inline-Status der Compiler-Ausgabe verfügbar, mit der Ausnahme, dass der Compiler bestimmte Objekte als sammelbar kennzeichnet, z Es sollte ein Fehler auftreten, wenn mehrere Symbole einen Namen gemeinsam verwenden, z. B. wenn die Hauptfunktion zweimal definiert wird. Nichts davon hat Einfluss auf den Code, den er generieren wird.

ISO/IEC 14882: 2014

Jedes Programm muss genau eine Definition von jedem Nicht-Inline enthalten Funktion oder Variable, die in diesem Programm odr verwendet wird; keine Diagnose erforderlich. Die Definition kann explizit im Programm erscheinen, sie kann im Standard oder in einer benutzerdefinierten Bibliothek gefunden werden oder (wenn geeignet) implizit definiert ist (siehe 12.1, 12.4 und 12.8). Eine Inline-Funktion muss in jeder Übersetzungseinheit definiert werden, in der sie verwendet wird.

0
isnullxbh

So habe ich es gemacht.

Datei A.h

#pragma once
#include "B.h"

class A {
    B b;
};

Datei B.h

#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 C.h

#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 "C.h" -Datei ein, um die getA () -Methode verwenden zu können. Die einzige Änderung des Originalcodes besteht darin, dass die getA () -Methode als öffentlich und nicht als privat definiert werden muss.

Wie viele von Ihnen erklärt haben, ist dies jedoch nicht wirklich nützlich.

0
Pascal Viguié