2015-09-29 14 views
6

Ich habe eine Liste von Zahlen.Kein passender Funktionsfehler beim Übergeben der Lambda-Funktion als Argument

Ich versuche, die Liste zu filtern und nur die positiven Zahlen zu behalten.

Ich versuche es zu tun, indem ich ein Lambda als Argument übergeben.

Ich frage mich, warum ich Funktion Mismatch-Fehler bekomme.

#include <vector> 
#include <algorithm> 
#include <functional> 

template<typename T> 
std::vector<T> keep(
     const std::vector<T> &original, 
     std::function<bool(const T&)> useful) 
{ 
    std::vector<T> out; 
    for(T item:original) 
    { 
     if(useful(item)) 
      out.push_back(item); 
    } 
    return out; 
} 

int main() 
{ 
    std::vector<int> a={4,6,2,-5,3,-8,13,-11,27}; 
    a=keep(a,[](const int& x)->bool{return x>0;}); 
    for(int y:a) 
    { 
     std::cout<<y<<std::endl; 
    } 
    return 0; 
} 

Und dies ist die Fehlermeldung:

error: no matching function for call to ‘keep(std::vector<int>&, main()::<lambda(const int&)>)’ 
    a=keep(a,[](const int& x)->bool{return x>0;}); 
               ^
+1

Sie können den tandard-Bibliotheksalgorithmus [std :: copy_if] (http://en.cppreference.com/w/cpp/algorithm/copy) dazu verwenden, dies viel einfacher zu tun: http: //coliru.stacked- crooked.com/a/99cdc73f48d19ba7 – Andrew

+0

Der Code in der Fehlermeldung stimmt nicht mit Ihrem Code überein. – molbdnilo

+0

Welchen Compiler benutzen Sie? –

Antwort

10

Ändern Sie die Funktion keep zu

template<typename T, typename Func> 
std::vector<T> keep(const std::vector<T> &original, 
        Func useful) 
{ 
    // code as usual 
} 

Live example.

Das funktioniert mit einem Argument zu useful einer dieser sein:

  • Lambda
  • std::function
  • functor
  • Funktionszeiger

Von the documentation:

Der Lambda-Ausdruck erstellt ein unbenanntes temporäres prvalue-Objekt eines eindeutigen unbenannten Nicht-Aggregat-Typs, der als Verschlusstyp bezeichnet wird.

Dies bedeutet, dass zwei Lambdas mit demselben Code zwei verschiedene typisierte Objekte generieren würden.

auto f1 = [](int) { return true; }; 
auto f2 = [](int) { return false; }; 
f2 = f1;        // error: no viable '=' 

jedoch diese beiden sind implizit konvertieren-Lage, die entsprechenden std::function Typen:

std::function<bool(int)> fn = f1; 
fn = f2; 

Aber dann, warum es nicht in Ihrem Fall? Dies liegt an der Voreinstellung des Vorlagentyps. Ändern keep zu

template<typename T> 
std::vector<T> keep(const std::vector<T> &original, 
        std::function<bool(const int &)> useful) 
// no type deduction for std::function's template, explicitly mentioned 

wird Ihr Beispiel ohne Besetzung an der Anrufer-Website zusammenstellen lassen.

Versuchen Sie jedoch, es mit std::function<T> übereinstimmen, wird nicht funktionieren, da Vorlagentyp Abzug keine Konvertierung berücksichtigt. Der Template-Argumentabzug sucht nach genauen Typübereinstimmungen. Implizite Konvertierungen spielen in diesem Stadium keine Rolle. Sie müssen es explizit auf einen passenden std::function als Atomic _ Alarm Kommentare werfen. Wie Joseph sagt in How to convert a lambda to an std::function using templates:

Vorlagentyp Abzug versucht, den Typ Ihrer Lambda-Funktion zum std::function<T> passen, die es einfach nicht in diesem Fall tun - diese Typen nicht gleich sind. Die Template-Typ-Ableitung berücksichtigt keine Conversions zwischen Typen.

Während in der alternativen Lösung, was ist so etwas wie dies geschieht:

auto f = [](int i) { return (i >= 0); } 

Die Art der f hier ist nicht std::function aber einige unbenannte Art abgeleitet, wie es wäre für die Template-Parameter Func oben.

Wenn Sie es immer noch die std::function Weg tun möchten, siehe this answer, die es mit einer zusätzlichen Vorlage-Indirektion tut. Weitere Informationen finden Sie unter this answer und this post.

+0

Danke. Ich frage mich immer noch, was mit meinem Code nicht stimmt? Wo habe ich einen Fehler gemacht? – ar2015

+2

@ ar2015, Lambda-Ausdruck hat seinen eigenen Typ, also explizit gegossen, oder eine Vorlage verwenden. IDEone: http://ideone.com/r2gYTh –

+0

@ ar2015 Der detaillierte Grund ist jetzt in der aktualisierten Antwort. – legends2k

Verwandte Themen