Ich habe eine Template-Funktion, die Funktionsobjekte empfängt. Manchmal sind die Funktionsobjekte statusfreie Strukturen, aber manchmal sind sie große zustandsbehaftete Objekte. Der Status des Funktionsobjekts wird in dieser Funktion nicht verändert, sondern nur geprüft. Ich bin auch sehr daran interessiert, Code zu schreiben, den der Compiler so weit wie möglich optimieren kann. Was sollte ich bei der Auswahl des Argumenttyps beachten?
Die Funktion ist von diesem Typ:
%Vor% Der Argumenttyp sollte wahrscheinlich funcT const & fun
sein, damit die großen Objekte nicht kopiert werden, aber warum verwenden die meisten Leute Call-by-Value-Funktionsobjekte? Verliere ich etwas durch Verwendung von const Referenz? Oder sollte ich Lvalue-Referenz verwenden? Bitte beachten Sie, dass c ++ 1y in Ordnung ist und dass das obige Codebeispiel nur ein Beispiel ist.
Der Argumenttyp sollte wahrscheinlich funktionieren const & amp; Spaß, so dass die große Objekte werden nicht kopiert,
Das ist nicht die Ansicht, die die Algorithmen in den Standardbibliotheken einnehmen. Dort werden aufrufbare Objekte nach Wert übernommen. Es liegt am Autor des aufrufbaren Objekts, sicherzustellen, dass es vernünftig billig zu kopieren ist. Zum Beispiel, wenn es Zugriff auf etwas Großes benötigt, dann können Sie den Benutzer des Funktors einen Verweis auf einen geben und diesen im Funktor speichern - das Kopieren einer Referenz ist billig.
Nun, es könnte sein, dass Sie die Dinge anders machen wollen als die Standard-Bibliothek, da Sie erwarten, dass Partikelherstellungsfunktionen ungewöhnlich schwer zu kopieren oder zu bewegen sind. Aber C ++ - Programmierer sind vertraut mit Funktoren, die kopiert werden. Wenn Sie also tun, was die Standard-Bibliothek tut, machen Sie normalerweise ihr Leben nicht schlechter als sie es schon waren. Das Kopieren von Funktoren ist kein Problem, es sei denn, Sie machen es zu einem: -)
Es gibt mehrere Anwendungsfälle, die alle verfügbar sein sollten:
Der Funktor hat keinen Status und wird als temporäres Objekt bereitgestellt: make_particle(MyFun())
Der Funktor hat einen Zustand, der später wiederhergestellt werden muss: YourFun f; make_particle(f);
Sie können beide Fälle nicht mit einem einzigen Referenztyp-Parameter lösen: Der erste Fall erfordert einen Const lvalue-Bezug oder einen rvalue-Bezug, der die zweite Verwendung verbietet, und der zweite Fall erfordert einen lvalue-Bezug, der die erste Verwendung verbietet / p>
Ein gängiges Idiom in solchen Situationen besteht darin, den Funktor nach Wert zu akzeptieren und am Ende zurückzugeben:
%Vor% In Ihrem Fall ist das vielleicht nicht ganz zutreffend, aber es ist eine Idee. Zum Beispiel könnten Sie std::pair<ParticleType, F>
zurückgeben. In jedem Fall müssten Sie Ihren Funktortyp kopierbar machen, aber das ist eine vernünftige Anforderung.
Eine Alternative, auf die von @Xeo hilfreich hingewiesen wird und die nur für die -Template verfügbar ist, ist, das funktor-Argument durch eine universelle Referenz zu verwenden, die in beiden Fällen funktioniert:
%Vor% Beachten Sie, dass wir in diesem Fall nicht std::forward
verwenden, da wir f
als echte Referenz verwenden und nicht einfach irgendwo anders weitergeben. Insbesondere dürfen wir uns nicht von f
bewegen, wenn wir es noch verwenden wollen.
Tags und Links c++ function-object