C++
Callable Objects
Suche…
Einführung
Aufrufbare Objekte sind die Auflistung aller C ++ - Strukturen, die als Funktion verwendet werden können. In der Praxis können Sie dies alles an die C ++ 17 STL-Funktion invoke () übergeben oder im Konstruktor von std :: function verwendet werden. Dazu gehören: Funktionszeiger, Klassen mit operator (), Klassen mit implizit Konvertierungen, Verweise auf Funktionen, Zeiger auf Elementfunktionen, Zeiger auf Elementdaten, Lambdas. Die aufrufbaren Objekte werden in vielen STL-Algorithmen als Prädikat verwendet.
Bemerkungen
Ein sehr nützliches Gespräch von Stephan T. Lavavej ( <funktional>: Neues und korrekte Verwendung ) ( Folien ) führt zur Basis dieser Dokumentation.
Funktionszeiger
Funktionszeiger sind die grundlegendste Art, Funktionen weiterzugeben, die auch in C verwendet werden können (weitere Informationen finden Sie in der C-Dokumentation ).
Für aufrufbare Objekte kann ein Funktionszeiger definiert werden als:
typedef returnType(*name)(arguments); // All
using name = returnType(*)(arguments); // <= C++11
using name = std::add_pointer<returnType(arguments)>::type; // <= C++11
using name = std::add_pointer_t<returnType(arguments)>; // <= C++14
Wenn wir einen Funktionszeiger zum Schreiben unserer eigenen Vektorsortierung verwenden würden, würde dies folgendermaßen aussehen:
using LessThanFunctionPtr = std::add_pointer_t<bool(int, int)>;
void sortVectorInt(std::vector<int>&v, LessThanFunctionPtr lessThan) {
if (v.size() < 2)
return;
if (v.size() == 2) {
if (!lessThan(v.front(), v.back())) // Invoke the function pointer
std::swap(v.front(), v.back());
return;
}
std::sort(v, lessThan);
}
bool lessThanInt(int lhs, int rhs) { return lhs < rhs; }
sortVectorInt(vectorOfInt, lessThanInt); // Passes the pointer to a free function
struct GreaterThanInt {
static bool cmp(int lhs, int rhs) { return lhs > rhs; }
};
sortVectorInt(vectorOfInt, &GreaterThanInt::cmp); // Passes the pointer to a static member function
Alternativ hätten wir den Funktionszeiger auf eine der folgenden Arten aufrufen können:
-
(*lessThan)(v.front(), v.back()) // All
-
std::invoke(lessThan, v.front(), v.back()) // <= C++17
Klassen mit Operator () (Functors)
Jede Klasse, die den operator()
überlädt, kann als Funktionsobjekt verwendet werden. Diese Klassen können von Hand geschrieben werden (oft als Funktoren bezeichnet) oder automatisch vom Compiler generiert, indem Lambdas ab C ++ 11 geschrieben werden.
struct Person {
std::string name;
unsigned int age;
};
// Functor which find a person by name
struct FindPersonByName {
FindPersonByName(const std::string &name) : _name(name) {}
// Overloaded method which will get called
bool operator()(const Person &person) const {
return person.name == _name;
}
private:
std::string _name;
};
std::vector<Person> v; // Assume this contains data
std::vector<Person>::iterator iFind =
std::find_if(v.begin(), v.end(), FindPersonByName("Foobar"));
// ...
Da Funktoren eine eigene Identität haben, können sie nicht in eine Typedef-Datei eingefügt werden, und diese müssen über ein Template-Argument akzeptiert werden. Die Definition von std::find_if
kann folgendermaßen aussehen:
template<typename Iterator, typename Predicate>
Iterator find_if(Iterator begin, Iterator end, Predicate &predicate) {
for (Iterator i = begin, i != end, ++i)
if (predicate(*i))
return i;
return end;
}
Ab C ++ 17 kann der Aufruf des Prädikats mit invoke: std::invoke(predicate, *i)
.