Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Function object
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== In C and C++ == Consider the example of a sorting routine that uses a callback function to define an ordering relation between a pair of items. The following C/C++ program uses function pointers: <!-- NOTE: For the compareInts() implementation below, see http://stackoverflow.com/a/10997428/1629102 for an explanation of why the more simple (int) a - (int) b would not work in all cases. --> <syntaxhighlight lang="c"> #include <stdlib.h> /* qsort() callback function, returns < 0 if a < b, > 0 if a > b, 0 if a == b */ int compareInts(const void* a, const void* b) { return ( *(int *)a - *(int *)b ); } ... // prototype of qsort is // void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *)); ... int main(void) { int items[] = { 4, 3, 1, 2 }; qsort(items, sizeof(items) / sizeof(items[0]), sizeof(items[0]), compareInts); return 0; } </syntaxhighlight> In C++, a function object may be used instead of an ordinary function by defining a class that [[operator overloading|overloads]] the [[function call operator]] by defining an <code>operator()</code> member function. In C++, this may appear as follows: <syntaxhighlight lang="cpp"> // comparator predicate: returns true if a < b, false otherwise struct IntComparator { bool operator()(const int &a, const int &b) const { return a < b; } }; int main() { std::vector<int> items { 4, 3, 1, 2 }; std::sort(items.begin(), items.end(), IntComparator()); return 0; } </syntaxhighlight> Notice that the syntax for providing the callback to the <code>std::sort()</code> function is identical, but an object is passed instead of a function pointer. When invoked, the callback function is executed just as any other member function, and therefore has full access to the other members (data or functions) of the object. Of course, this is just a trivial example. To understand what power a functor provides more than a regular function, consider the common use case of sorting objects by a particular field. In the following example, a functor is used to sort a simple employee database by each employee's ID number. <syntaxhighlight lang="cpp"> struct CompareBy { const std::string SORT_FIELD; CompareBy(const std::string& sort_field="name") : SORT_FIELD(sort_field) { /* validate sort_field */ } bool operator()(const Employee& a, const Employee& b) const { if (SORT_FIELD == "name") return a.name < b.name; else if (SORT_FIELD == "age") return a.age < b.age; else if (SORT_FIELD == "idnum") return a.idnum < b.idnum; else /* throw exception or something */ } }; int main() { std::vector<Employee> emps; /* code to populate database */ // Sort the database by employee ID number std::sort(emps.begin(), emps.end(), CompareBy("idnum")); return 0; } </syntaxhighlight> In [[C++11]], the lambda expression provides a more succinct way to do the same thing. <syntaxhighlight lang="cpp"> int main() { std::vector<Employee> emps; /* code to populate database */ const std::string sort_field = "idnum"; std::sort(emps.begin(), emps.end(), [&sort_field](const Employee& a, const Employee& b) const { /* code to select and compare field */ }); return 0; } </syntaxhighlight> It is possible to use function objects in situations other than as callback functions. In this case, the shortened term ''functor'' is normally ''not'' used about the function object. Continuing the example, <syntaxhighlight lang="cpp"> IntComparator cpm; bool result = cpm(a, b); </syntaxhighlight> In addition to class type functors, other kinds of function objects are also possible in C++. They can take advantage of C++'s member-pointer or [[generic programming|template]] facilities. The expressiveness of templates allows some [[functional programming]] techniques to be used, such as defining function objects in terms of other function objects (like [[function composition (computer science)|function composition]]). Much of the C++ [[Standard Template Library]] (STL) makes heavy use of template-based function objects. Another way to create a function object in C++ is to define a non-explicit conversion function to a function pointer type, a function [[reference (C++)|reference]] type, or a reference to function pointer type. Assuming the conversion does not discard [[Type qualifier|cv-qualifiers]], this allows an object of that type to be used as a function with the same [[function signature|signature]] as the type it is converted to. Modifying an earlier example to use this we obtain the following class, whose instances can be called like function pointers:<ref>{{cite web|url=https://en.cppreference.com/w/cpp/language/overload_resolution#Call_to_a_class_object|title=Overload resolution§Call to a class object|website=cppreference.com}}</ref> <syntaxhighlight lang="cpp"> // comparator predicate: returns true if a < b, false otherwise struct IntComparator { static bool compare(const int &a, const int &b) { return a < b; } using T = decltype(compare); operator T*() const { return compare; } }; int main() { std::vector<int> items { 4, 3, 1, 2 }; std::sort(items.begin(), items.end(), IntComparator()); return 0; } </syntaxhighlight> === Maintaining state === Another advantage of function objects is their ability to maintain a state that affects <code>operator()</code> between calls. For example, the following code defines a [[generator (computer science)|generator]] counting from 10 upwards and is invoked 11 times. <syntaxhighlight lang="cpp"> #include <algorithm> #include <iostream> #include <iterator> class CountFrom { public: CountFrom(int count) : count_(count) {} int operator()() { return count_++; } private: int count_; }; int main() { const int state(10); std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 11, CountFrom(state)); } </syntaxhighlight> In C++14 or later, the example above could be rewritten as: <syntaxhighlight lang="cpp"> #include <algorithm> #include <iostream> #include <iterator> int main() { std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 11, [count=10]() mutable { return count++; }); } </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)