2009-07-07 8 views
7

Ich versuche, die derzeit akzeptierten Funktionen von C++ 11 zu lernen, und ich habe Probleme mit Auto und Decltype. Als Lernübung erweitere ich die Klasse der Std-Klassen um einige generische Funktionen.Verwendung von Auto und Decltype in C++ 11

Für die Elementzuordnung soll der Rückgabetyp generisch sein, abhängig davon, was die übergebene Funktion zurückgibt. Für den Rückgabetyp könnte ich so etwas tun.

auto map(const function<float (_Ty)>& f) -> FList<decltype(f(_Ty))>* 

Dies müsste auch den Float-Typ in der Funktionsvorlage entfernen.

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>* 

Ich könnte eine Template-Klasse verwenden, aber das macht die Verwendung von Instanzen ausführliche, da ich den Rückgabetyp angeben.

template<class T> FList<T>* map(const function<T (_Ty)>& f) 

Zusammengefasst meiner Frage, um herauszufinden, ich versuche, wie Karte zu definieren, ohne eine Vorlage-Klasse und haben immer noch generische es in der Art er zurückkehrt.

Antwort

17

Abgeleitet von std::list oder anderen std:: Behältern wird abgeraten.

Schreiben Sie Ihre Operationen als freie Funktionen, so dass sie über Iteratoren auf jedem Standardcontainer arbeiten können.

Meinst du "Karte ohne Verwendung einer Vorlagenfunktion definieren"?

Sie sollten in der Lage sein, den Mitgliedstyp std::function zu verwenden, um den zurückgegebenen Typ zu erhalten.

Außerdem müssen Sie nicht angeben, dass die Funktion als std::function übergeben wird. Sie können es als einen beliebigen Typ offen lassen und den Compiler beitreten lassen. Sie benötigen nur std::function für Laufzeit-Polymorphismus.

Und mit neuen, um rohe Heap-allocation-Objekte zu erstellen und sie per Zeiger zurückgeben ist soooo 1992! :)

Ihre Iter-Funktion ist im Wesentlichen die gleiche Sache wie die range-based for loop.

Aber all das beiseite ... meinst du sowas?

Dies wird alle aufrufbaren Daten abgleichen und den Rückgabetyp der Funktion mit declltype herausfinden.

Beachten Sie, dass es erforderlich ist, dass _Ty standardmäßig konfigurierbar ist. Sie können durch die Herstellung einer Instanz um das zu bekommen:

template <class T> 
T make_instance(); 

Keine Umsetzung erforderlich ist, da kein Code erzeugt wird, dass es nennt, so die Linke hat nichts zu bemängeln

(dank dribeas für den Hinweis!)

So, jetzt der Code wird:

FList<decltype(f(make_instance<_Ty>()))>* 

Oder wörtlich, eine Liste der unabhängig von der Art wäre Sie von dem Aufruf der Funktion f mit einem Verweis auf eine Instanz von _Ty bekommen würde.

Und als kostenloser Bonus für die Annahme, rvalue Referenzen sehen - das bedeutet, dass Sie schreiben:

std::list<C> make_list_somehow() 
{ 
    std::list<C> result; 
    // blah... 
    return result; 
} 

Und es dann so nennen:

std::list<C> l(make_list_somehow()); 

Weil std :: Liste wird einen "Move-Konstruktor" haben (wie ein Kopierkonstruktor, aber gewählt, wenn das Argument ein temporäres ist, wie hier), kann es den Inhalt des Rückgabewerts stehlen, dh mache dasselbe wie ein optimales swap. Es gibt also kein Kopieren der gesamten Liste. (Deshalb wird C++ 0x dafür sorgen, dass naiv geschriebener existierender Code schneller läuft - viele populäre aber hässliche Performance-Tricks werden obsolet).

Und Sie können die gleiche Art von Sache kostenlos für jede vorhandene Klasse Ihrer eigenen, ohne einen korrekten Move-Konstruktor zu schreiben, mit unique_ptr.

std::unique_ptr<MyThing> myThing(make_my_thing_somehow()); 
+1

ich versuche zu lernen, wie man auto und declltype nicht nach Best Practices fragen. – gradbot

+3

Ja, aber es gibt eine Menge anderer Sachen, von denen Sie vermutlich auch profitieren würden. Ich war vorher auf einer Zugreise, also wurde ich unterbrochen, bevor ich zu den entschlüsselten Sachen kam. Jetzt aktualisiert. –

+0

Super danke! – gradbot

0

Sie können nicht automatisch in Funktionsargumente verwenden, in denen Sie die Typen der Argumente wollen abgeleitet werden. Sie verwenden Vorlagen dafür. Schauen Sie sich an: http://thenewcpp.wordpress.com/2011/10/18/the-keyword-auto/ und http://thenewcpp.wordpress.com/2011/10/25/decltype-and-declval/. Sie erklären beide, wie man auto und declltype verwendet. Sie sollten Ihnen genügend Informationen darüber geben, wie sie verwendet werden. Insbesondere könnte eine andere Antwort über make_instance mit declval besser gemacht werden.

0

Ich denke, der Punkt, den Jarrah in seiner Antwort machte, ist, dass diese Punkte genau erklären, wie man diese Dinge benutzt. Ich werde die Details sowieso hinweisen:

Sie das nicht tun können, gibt es zwei Dinge falsch:

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>* 

auto kann nicht für Funktionsargumente verwendet werden. Wenn Sie möchten, dass der Typ der Funktion abgeleitet wird, sollten Sie Vorlagen verwenden. Die zweite ist, dass decltype einen Ausdruck verwendet, während _Ty ein Typ ist. Hier ist, wie man es löst:

template <typename Ret> 
auto 
map(const function<Ret (_Ty)>& f) 
    -> FList<decltype(f(declval<_Ty>()))> 
{} 

Auf diese Weise gibt es keine Magie, um eine Instanz eines Typs zu erstellen.