Wenn ich diese Funktion definieren,C++ 11 nicht Typen ableiten, wenn std :: Funktion oder Lambda-Funktionen beteiligt sind
template<class A>
set<A> test(const set<A>& input) {
return input;
}
ich es test(mySet)
an anderer Stelle im Code verwenden, ohne explizit die anrufen definieren Vorlagentyp Aber wenn ich die folgende Funktion:
template<class A>
set<A> filter(const set<A>& input,function<bool(A)> compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
Wenn ich diese Funktion aufrufen mit filter(mySet,[](int i) { return i%2==0; });
bekomme ich folgende Fehlermeldung:
error: no matching function for call to ‘filter(std::set&, main()::)’
jedoch alle diese Versionen tun Arbeit:
std::function<bool(int)> func = [](int i) { return i%2 ==0; };
set<int> myNewSet = filter(mySet,func);
set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; });
set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;}));
Warum kann C++ 11 den Schablonentyp nicht erraten, wenn ich die Lambda-Funktion direkt anlege? y innerhalb des Ausdrucks ohne direkt eine std::function
zu erstellen?
EDIT:
Per Beratung von Luc Danton in den Kommentaren, hier ist eine Alternative zu der Funktion hatte ich früher, die nicht die Vorlagen benötigt explizit übergeben werden.
template<class A,class CompareFunction>
set<A> filter(const set<A>& input,CompareFunction compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
Dies kann durch set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; });
, ohne dass die Vorlage aufgerufen werden.
Der Compiler kann sogar die Rückgabetypen in gewissem Umfang erraten, indem er das neue Schlüsselwort decltype verwendet und die Syntax des neuen Funktionsrückgabetyps verwendet. Hier ist ein Beispiel, das einen Satz auf einer Karte konvertiert, unter Verwendung einer Filterfunktion und eine Funktion, die die Schlüssel auf der Grundlage der Werte erzeugt:
template<class Value,class CompareType,class IndexType>
auto filter(const set<Value>& input,CompareType compare,IndexType index) -> map<decltype(index(*(input.begin()))),Value> {
map<decltype(index(*(input.begin()))),Value> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret[index(*it)] = *it;
}
}
return ret;
}
Es kann auch ohne Verwendung der Schablone direkt aufgerufen werden, wie
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
Nicht verwandt mit Ihrer Frage, aber Sie erkennen, dass Ihr 'Filter' ist im Wesentlichen äquivalent zu einer nicht-generischen Version von' std :: copy_if', nicht wahr? –
Ah, mir war std :: copy_if nicht bekannt, danke, dass du darauf hinweist. Dies ist jedoch Teil einer größeren Gruppe von 4 Funktionen, eine, die set => map während der Filterung konvertiert, und ich sehe keine Möglichkeit, das mit copy_if zu implementieren und dem Benutzer zu erlauben, Schlüssel unter Verwendung der Werte in der Menge zu erzeugen. Aus Gründen der Konsistenz verwende ich es auf diese Weise. – Datalore
Wenn Sie einen Funktor akzeptieren möchten, ist es normalerweise idiomatisch, ihn zu einem allgemeinen Template-Parameter zu machen, d. H. 'Template Set Filter (Set Const & Eingabe, Prädikat vergleichen);'. Wie Sie gerade gesehen haben, funktioniert 'std :: function' nicht, um zu dokumentieren, dass das übergebene Prädikat eine Signatur haben sollte, die mit' bool (A) 'übereinstimmt; Es gibt andere Möglichkeiten, dies zu tun. Außerdem gibt es * andere * Nachteile bei der Verwendung von 'std :: function' als Funktionsargument. –