Ist es sinnvoll, Inline-Schlüsselwörter mit Vorlagen zu verwenden?

119

Ist es sinnvoll, Vorlagen in Headern zu definieren und der Compiler zu bestimmen, ob das Inlining einer Funktion vorteilhaft ist? Ich habe gehört, dass moderne Compiler besser wissen, wann sie eine Funktion einbinden müssen, und inlineHinweise ignorieren .


edit: Ich möchte beide Antworten akzeptieren, aber das ist nicht möglich. Um das Problem zu schließen, akzeptiere ich die Antwort von phresnel , da sie die meisten Stimmen erhalten hat und er formal Recht hat, aber wie ich in den Kommentaren erwähnt habe, betrachte ich die Antworten von Puppy und Component 10 aus verschiedenen Blickwinkeln auch als richtig .

Das Problem liegt in der C ++ - Semantik, die bei inlineSchlüsselwörtern und Inlining nicht streng ist . phresnel sagt "schreibe inline, wenn du es ernst meinst", aber was eigentlich damit gemeint inlineist, ist nicht klar, da es sich von seiner ursprünglichen Bedeutung zu einer Direktive entwickelt hat, die "Compiler davon abhält, über ODR-Verstöße zu meckern", wie Puppy sagt.

doc
quelle

Antworten:

95

Es ist nicht irrelevant. Und nein, nicht jede Funktionsvorlage ist inlinestandardmäßig. Der Standard ist sogar explizit in der expliziten Spezialisierung ([temp.expl.spec])

Haben Sie Folgendes:

a.cc

#include "tpl.h"

b.cc.

#include "tpl.h"

tpl.h (entnommen aus Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Kompiliere dies, et voila:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

inlineWenn Sie bei der expliziten Instanziierung nicht angeben , kann dies ebenfalls zu Problemen führen.

Zusammenfassend : Bei nicht vollständig spezialisierten Funktionsvorlagen, dh solchen, die mindestens einen unbekannten Typ enthalten, können Sie inlineFehler weglassen und nicht empfangen, dies ist jedoch nicht der Fall inline. Bei vollständigen Spezialisierungen, dh solchen, die nur bekannte Typen verwenden, können Sie diese nicht auslassen.

Vorgeschlagene Faustregel : Schreiben inlineSie, wenn Sie es ernst meinen, und seien Sie einfach konsequent. Sie denken weniger darüber nach, ob Sie es tun sollen oder nicht, nur weil Sie es können. (Diese Faustregel entspricht der C ++ - Vorlage von Vandevoorde / Josuttis : The Complete Guide ).

Sebastian Mach
quelle
2
Man hätte schreiben können, stimmt. Aber das bedeutet keine Inlinenität, auch wenn es so aussieht. Vandevoorde und Josuttis geben auch genau das in C ++ - Vorlagen an: Der vollständige Leitfaden
Sebastian Mach
42
Die explizite Spezialisierung ist keine Vorlage.
Welpe
2
@DeadMG: Eine normale Funktion wird jedoch bei der Suche einer vollständigen Spezialisierung vorgezogen. Wenn es sich also nicht um eine Vorlage oder eine Nichtvorlage handelt, welche sind sie dann?
Sebastian Mach
12
Diese Antwort ist falsch. Eine explizite Spezialisierung einer Vorlage ist eine Funktion, keine Vorlage. Diese Funktion wird nicht inlinenur, weil die spezialisierte Vorlage mit markiert ist inline. So inlineauf der Schablone ist völlig irrelevant. Ob diese Funktion sein sollte inlineoder nicht, hat nichts damit zu tun, dass sie über eine Vorlagenspezialisierung generiert wird (und es gibt bessere Antworten als diese, die angeben, wann sie verwendet werden soll inline). Die Antwort von @Puppy unten ist richtig, diese nicht. Das Hinzufügen inlineeiner Vorlage ist irrelevant und clang-tidywird tatsächlich entfernt.
Gnzlbg
6
Das Beispiel zeigt auch nur ODR-Probleme für normale Funktionen (das Verhalten dort hat nichts mit Vorlagen zu tun). Um zu zeigen, dass dies inlinenicht irrelevant ist, sollte das Beispiel den Fall einer expliziten Spezialisierung template<> void f<>(int) {} ohne das inlineSchlüsselwort abdecken . Aber selbst dann macht das Ändern des inlineBezeichners in der Vorlage keinen Unterschied, da inlinees unerheblich ist , ob Sie die Vorlage markieren oder nicht.
Gnzlbg
34

Es ist irrelevant. Alle Vorlagen sind bereits vorhanden inline- ganz zu schweigen davon, dass das inlineSchlüsselwort ab 2012 nur verwendet wird, um zu verhindern, dass Compiler über ODR-Verstöße meckern. Sie sind absolut korrekt - Ihr Compiler der aktuellen Generation weiß, was er selbst einbinden muss, und kann dies wahrscheinlich auch zwischen Übersetzungseinheiten tun.

Hündchen
quelle
11
Der Standard besagt nicht, dass alle Vorlagen inline sind.
Sebastian Mach
16
@phresnel: Vorlagen haben jedoch dieselbe Semantik wie inlinemarkierte Funktionen (dh, es können mehrere äquivalente Definitionen an den Linker übergeben werden, der eine auswählt). Das, nicht Inlining, ist die eigentliche Funktion des inlineSchlüsselworts.
Ben Voigt
2
@ BenVoigt: Ich weiß um die ODR-Bedeutung von inline. Vielleicht werfen Sie einen Blick auf meine Antwort unten (oder oben, je nach gewählter Sortierung). Bei nicht spezialisierten Vorlagen haben Sie natürlich Recht, aber formal ist es nicht dasselbe.
Sebastian Mach
3
@DeadMG: In C ++ ist es nicht erforderlich, dass eine Funktionsvorlage in einer Header-Datei implementiert wird. es kann überall implementiert werden. Um dies widerzuspiegeln, empfehle ich, das zu markieren, inlinewas inline sein soll. Es macht normalerweise keinen Unterschied, aber auf Standard sind sie nicht gleich und sie sind nicht alle inline. Ich akzeptiere Ihre Haltung dazu und sage "Es ist irrelevant", aber laut Standard sind nicht alle Vorlagen inline, nur für Sie als C ++ - Benutzer erscheinen sie so, als ob.
Sebastian Mach
7
Ihr Kommentar zu der akzeptierten Antwort, dass explizite Spezialisierung keine Vorlage ist (was natürlich offensichtlich ist, nachdem Sie dazu aufgefordert wurden ...), ist vielleicht die hilfreichste Sache auf dieser Seite. Würde es Ihnen etwas ausmachen, es auch Ihrer Antwort hinzuzufügen?
Kyle Strand
6

Wie Sie vorgeschlagen haben, inlineist ein Hinweis auf den Compiler und nichts weiter. Es kann wählen, ob es ignoriert oder Inline-Funktionen verwendet werden sollen, die nicht als Inline markiert sind.

Die Verwendung inlinemit Vorlagen war früher eine (schlechte) Methode, um das Problem zu umgehen, dass jede Kompilierungseinheit ein separates Objekt für dieselbe Vorlagenklasse erstellt, das dann zum Zeitpunkt der Verknüpfung zu Duplizierungsproblemen führt. Durch die Verwendung inline(glaube ich) funktioniert das Namens-Mangeln anders, wodurch der Namenskonflikt zur Link-Zeit umgangen wird, jedoch auf Kosten von stark aufgeblähtem Code.  

Marshall Cline erklärt es hier besser als ich.

Komponente 10
quelle
@Xeo: Das war früher nicht der Fall. Überprüfen Sie hier: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… Ich gehe davon aus, dass sich dies in letzter Zeit geändert hat. Deshalb habe ich in der Vergangenheitsform gesprochen.
Komponente 10 10.
2
@Xeo: Können Sie mich auf den Teil von The Standard verweisen, der besagt, dass Funktionsvorlagen immer inline sind? Weil sie es nicht sind.
Sebastian Mach
@phresnel: Interessant, ich könnte schwören, dass ich das im Standard gelesen habe. Vielleicht habe ich es mit der Tatsache verwechselt, dass Funktionsvorlagen vom ODR ( §14.5.5.1 p7 & p8) ausgenommen sind . Mein schlechtes, ich habe den falschen Kommentar entfernt.
Xeo
@ Komponente 10 Warum Sie denken, es ist schlecht, um Kompilierungsproblem zu umgehen
Kapil