2014-01-20 8 views
8

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?Was ist der korrekte Argumenttyp für ein Funktionsobjekt?

Die Funktion ist von dieser Art:

template<typename funcT> 
auto make_particle(funcT fun) { 
    Particle<typename funcT::result_type> particle; 
    particle = fun(); 
    return particle; 
} 

Das Argument Typ wahrscheinlich funcT const & fun sein sollte, so dass die großen Objekte nicht kopiert werden, aber warum die meisten Menschen Objekte Call-by-Value-Funktion verwenden? 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.

Antwort

5

Das Argument Typ sollte wahrscheinlich sein FKT const & Spaß, so dass die große Objekte nicht kopiert werden,

Das ist nicht der Blick durch die Algorithmen in den Standardbibliotheken aufgenommen ist. Dort werden aufrufbare Objekte nach Wert übernommen. Es liegt am Autor des Callable-Objekts zu gewährleisten, 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 dazu bringen, einen Verweis auf einen zu geben und diesen im Funktor zu speichern - das Kopieren einer Referenz ist billig.

Nun mag es sein, dass Sie Dinge anders als die Standardbibliothek machen wollen, weil 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, dann machen Sie normalerweise ihr Leben nicht schlimmer als sie es schon waren. Kopieren von Funktoren ist kein Problem, es sei denn, Sie machen es zu einem :-)

7

Es gibt mehrere Anwendungsfälle, die alle zur Verfügung stehen sollten:

  • Der Funktor keinen Zustand und wird als vorübergehende geliefert: make_particle(MyFun())

  • Der Funktor einen Zustand hat, die sein muss später zurückgewonnen: YourFun f; make_particle(f);

Sie können nicht beide Fälle mit einem einzigen Referenztypparameter lösen: Der erste Fall r setzt einen Const-Wert-Bezugswert oder einen R-Wert-Bezugswert, der den zweiten Gebrauch verbietet, und der zweite Fall erfordert einen L-Wert-Bezug, der den ersten Gebrauch verbietet.

Ein gemeinsames Idiom in solchen Situationen ist der Funktor von Wert zu übernehmen, und zurückgeben am Ende:

template <typename Iter, typename F> 
F map(Iter first, Iter last, F f) 
{ 
    // ... f(*first) ... 
    return f; 
} 

, die nicht ganz in Ihrem Fall anwendbar sein kann, obwohl, aber es ist eine Idee . Zum Beispiel könnten Sie eine 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 wies helfend durch @Xeo aus, und für Funktion Vorlagen nur, ist das Funktors Argument durch allgemeine Bezugnahme auf nehmen, was in beiden Fällen funktioniert:

template <typename Iter, typename F> 
void map(Iter first, Iter last, F && f) 
{ 
    // ... use f(*first) ... 
} 

Beachten Sie, dass in In diesem Fall tun wir nicht verwenden std::forward, da wir f als eine echte Referenz verwenden, und nicht nur um es durch woanders zu übergeben. Insbesondere dürfen wir uns nicht bewegen - von f, wenn wir es noch verwenden wollen.

+1

Sie können beide Fälle mit einem einzigen Referenzparameter lösen - T &&, auch bekannt als universelle Referenzen. – Xeo

+0

@Xeo: Anfangs dachte ich über eine einzige * Funktion * nach, keine Vorlage, also suchte ich nach einer einzigen Lösung. Sie haben natürlich Recht, da wir bereits Vorlagen haben, können wir sie auch verwenden. –

Verwandte Themen