2017-10-11 2 views
0

Von this Frage Ich habe ein gutes Verständnis von Funktoren (Funktionsobjekte); wie man sie initialisiert und anruft. Ich schrieb einen Code mit diesem für mein eigenes VerständnisWarum schlägt die Verwendung eines Funktionsobjektarguments in std :: transform fehl und erfordert stattdessen einen Lambda-Ausdruck

class Foo 
{ 
private: 
    int x; 
public: 
    Foo(int x) : x(x) {} 
    int operator()(int y) { return x + y; } 
}; 

Foo poo(50); 

int a = poo(50); 

std::cout << a; 

std::vector<int> vec(10); 
std::vector<int> pec(10); 

std::transform(vec.begin(), vec.end(), vec.begin(), poo(1)); 

zu spielen, um und erhalten die folgenden Kompilierungsfehler

Severity Code Description Project File Line Suppression State 
Error C2064 term does not evaluate to a function taking 1 arguments 

ich einige der Kommentare innerhalb der obigen Frage sah und versuchte stattdessen einen Lambda-Ausdruck

std::transform(vec.begin(), vec.end(), vec.begin(), [](Foo poo) {return poo(1); });

, die funktioniert, aber ich verstehe nicht, warum die akzeptierte Antwort std::transform(in.begin(), in.end(), out.begin(), add_x(1)); mit schlägt fehl. Warum muss ich einen Lambda-Ausdruck verwenden? Eine andere Antwort ist dasselbe, aber es wird immer noch zu einem Kompilierungsfehler führen. Warum das?

+9

Es klingt wie ein Tippfehler. 'poo (1)' -> 'Foo (1)'. –

+0

Ich denke, es ist eher ein Fall der etwas irreführenden Fehlermeldung, die Sie die Tatsache vermissen lässt, dass Sie auf etwas verweisen, das nicht existiert: 'poo'. –

+1

'poo (1)' ist ein 'int'; wie die Fehlermeldung sagt, es ist keine Funktion, 1 Argument zu nehmen. 'Foo (1)' ist ein Funktionsobjekt mit einem 'operator()', der ein einzelnes Argument vom Typ 'int' akzeptiert. –

Antwort

3

Dieser Code funktioniert einwandfrei.

#include <iostream> 
#include <array> 

class add_x 
{ 
private: 
    int x; 

public: 
    add_x(int x) : x(x) {} 

    int operator()(int y) /* consider adding const here */ 
    { return x + y; } 
}; 


int main() 
{ 
    std::array<int, 5> input { 1, 4, 9, 16, 25 }; 
    std::array<int, 5> output; 
    std::transform(begin(input), end(input), begin(output), add_x(1)); 
    for (auto& val : output) std::cout << val << "\n"; 
} 

Allerdings ist es wahrscheinlich eine gute Idee des Aufruf einer const Member-Funktion zu machen, da sie nicht den Funktors nicht mutieren. Das kann auch dazu führen, dass es mit mehr Versionen der Standardbibliothek funktioniert.

Der Unterschied zwischen dieser und Ihrer Lambda-Version besteht darin, dass hier die Konstante 1 an den Konstruktor übergeben wird, um ein Funktorobjekt zu erstellen, und die Daten sequenziell an den Operator dieser einzelnen Funktorinstanz übergeben werden. In Ihrem Lambda wird ein neues Objekt aus jedem Datum durch Aufrufen des Konvertierungskonstruktors erstellt, und dann wird die Konstante an den Operator übergeben. Das heißt, x und y werden durch Ihre Problemumgehung ausgetauscht und auch die Anzahl der Instanzen geändert.

1

Es funktioniert auch, wenn Sie eine Definition hinzufügen:

Foo poo(1); 

und nur poo senden in transformieren, ohne die (1) Aufruf. Transform erfordert ein Objekt mit einem() -Operator, um es aufzurufen, und wenn man es separat deklariert, wird es ein wenig klarer, was sein Umfang ist.

+0

yeah definieren 'Foo poo (1)' und dann in den Transformator 'poo' gehen. Gute Idee. – Mushy

Verwandte Themen