2017-01-16 1 views
1

Lassen Sie uns sagen, ich habe diese Funktion: (die so ziemlich eine Funktion im Container auf jeden Wert läuft, und dann liefert einen Vektor des Ergebnisses jeder Iteration)Wie kann const und nicht-const Typ ohne duplizierende Funktionen abgeleitet werden?

#include <vector> 
using std::vector; 

template<class F, class V> 
auto vmap(const F &f, const V &v) -> vector<decltype(f(v[0]))> { 
    vector<decltype(f(v[0]))> result; 
    result.reserve(v.size()); 
    for (auto &p : v) 
     result.push_back(f(p)); 
    return result; 
} 

ich es so nicht nennen kann:

vector<int> vint = {1,2,3,4,5}; 
vmap([](auto &p) {return p++;},vint); 

Da die parametrierte vectorconst ist, um sie geschehen ich erstellen müssen zwei vmap, die nicht bekommen constV und eine, die const ist.

Es fühlt sich zu sehr an, wenn mehrere Container/vector an eine Funktion übergeben werden, weil es mich dazu bringt, 2^containers_count Funktionen zu schreiben.

Gibt es irgendeine (-dirty but working) Lösung dafür?

Antwort

4

Sie eine Weiterleitung Verweis auf beiden normalen l-Wert Referenzen (beispielsweise std::vector<int>&) und r-Wert Referenzen (std::vector<int>&&) zu binden, verwenden könnten.

Der Nachteil ist, dass Sie nie in der Lage sind, nach Wert zu übergeben (nur ref, const ref oder r-Wert ref), obwohl ich glaube nicht, dass ein Problem für Sie sein wird:

template<class F, class V> 
auto vmap(F&& f, V&& v) { 
    vector<decltype(f(v[0]))> result; 
    result.reserve(v.size()); 
    for (auto& p : v) 
     result.push_back(f(p)); 
    return result; 
} 

Demo

Beachten Sie, dass das Lambda Sie passieren muß sowohl const anwendbar sein, wenn Sie einen const Container (Danke, Miles) passieren gehen, so p++ ist die Frage aus (Obwohl aufpassen, dass eine Vorlage Instanziierung modifiziert die Eingabe und die andere nicht, was möglicherweise unerwartet ist):

vector<int> vint = {1,2,3,4,5}; 
vmap([](auto &p) {return p++;},vint); 
const std::vector<int> vint2 = vint; 
vmap([](auto &p) {return p+1;},vint2); 
+1

Zur Erinnerung: Der Funktor muss nur auf "const" angewendet werden, wenn Sie einen Const-Container übergeben. [Beispiel] (http://coliru.stacked-crooked.com/a/858852c55432fb6c) –

+0

@MilesBudnek: Messzeitpunkt – AndyG

+0

Das ist ziemlich nah, aber wenn ich 'lvalue' übergebe, heißt es nicht, dass es ein schreibgeschütztes Objekt ist. – LyingOnTheSky

1

Wenn Sie zulassen möchten, dass Ihre Funktionen den Vektor ändern, entfernen Sie die const aus den Parametern Ihrer Funktion. Die Konstanz von v wird aus dem Argument abgeleitet, das ihr gegeben wird.

Sie müssen auch den Rückgabetyp nicht angeben, er wird aus der return-Anweisung abgeleitet.

template<class F, class V> 
auto vmap(const F &f, V &v) { 
    vector<decltype(f(v[0]))> result; 
    result.reserve(v.size()); 
    for (auto&p : v) 
     result.push_back(f(p)); 
    return result; 
} 

Beachten Sie, dass result.reserve(v.size()); nur für std::vector arbeiten. Wenn Sie Ihren Algorithmus verallgemeinern wollen, müssen Sie diese Zeile entfernen oder sich darauf spezialisieren.

+0

* Sie müssen auch den Rückgabetyp nicht angeben, er wird von der return-Anweisung abgeleitet. * Nur in C++ 14, C++ 11 nicht. –

+0

Ich habe: 'ungültige Initialisierung von nicht-const Referenz des Typs 'std :: vector &' von einem rvalue des Typs 'std :: vector ' ' – LyingOnTheSky

+0

Siehe [diese Antwort] (http: // stackoverflow.com/a/41683306/7359094) von AndyG, wie es vollständiger ist. –

0

Sie könnten entweder ein Lambda verwenden, das einen konstanten Vektor annimmt. Für Ihr Beispiel:

vmap([](const auto &p) {return p+1;}, vint); 

Oder vmap ändern, dass es nicht einen konstanten Vektor erfordert. Für Ihr Beispiel:

auto vmap(const F &f, V &v) 
Verwandte Themen