TDDD38 APiC++ Standard Library – Function objects and lambda expressions 288 Function objects and lambda expressions • function objects are objects of class type with the function call operator overloaded – operator() must be a non-static member function • important for effective use of the standard library – enables algorithms to work with both ordinary functions and function objects template<class InputIterator, class Function> Function for_each(InputIterator first, InputIterator last, Function f); for_each(begin(v), end(v), fun); for_each(begin(v), end(v), fun_obj{}); – increases the expressive power of the library • function objects are more flexible and powerful than functions – can have data members to keep a state – can have other member functions than operator() – makes the resulting code more effective transform(begin(v), end(v), std::negate<double>{}); // negate object can be inlined • lambda expressions is a convenient way to create simple function objects inplace – in many situations in C++98 where function objects was used, lambda expressions should be used in C++11 File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 289 Regarding exam • important to have a good understanding of function objects and lambda expressions – know about the standard library function objects – be able to define own function objects when needed – sufficient practice in using function objects, both from standard library and your own, in combination with other components – lambdas is often a good alternative to create simple function objects • cplusplus.com Reference will be available at exam (web browser) • see the course examination page for more information File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 290 Defining function object class types • defining a simple, binary function object class template<typename T> struct logical_xor { constexpr bool operator()(const T& lhs, const T& rhs) const { return (lhs && !rhs) || (!lhs && rhs); } using first_argument_type = T; using second_argument_type = T; using result_type = bool; }; – constexpr allows locical_xor be evaluated during compile-time, for appropriate arguments – constexpr also implies inline – the alias declarations (type definitions) are required by some library components, e.g., for declaring function parameters and other stuff File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 291 Using function objects #include <iostream> #include <functional> #include <iterator> #include <vector> using namespace std; int main() { vector<bool> b1{ false, false, true, true }; vector<bool> b2{ false, true, false, true }; vector<bool> b3; transform(begin(b1), end(b1), begin(b2), back_inserter(b3), logical_xor<bool>{}); // b3 now contain b1 xor b2 (bit-wise) return 0; } • the expression logical_xor<bool>{} creates a temporary object – passed to the corresponding parameter, binary_op – the function call in transform is binary_op(*first1, *first2); – can be either an ordinary function, a function object, or a lambda expression File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 292 Function objects with state • Fibonacci number generator (F0 = 0, F1 = 1, Fn = Fn-1 + Fn-2 for n>1) class Fibonacci { public: Fibonacci() : Fn{0}, Fn_1{1} {} unsigned long long int operator()() const { unsigned long long int next{Fn}; Fn = Fn_1; Fn_1 = next + Fn; return next; } private: mutable unsigned long long int Fn; mutable unsigned long long int Fn_1; }; vector<unsigned long long int> v(20); generate(begin(v), end(v), Fibonacci{}); File: Standard-Function-Objects-OH-en // 0, 1, 1, 2, 3, 5, 8, … © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 293 Standard library function object classes • the standard library declares function objects classes correspond to the arithmetic, comparison and logical operators. plus minus multiplies divides modulus negate addition subtraction multiplication division reminder from integer division negation – performs x + x x * x / x % -x equal_to not_equal_to greater less greater_equal less_equal equality inequality greater-than less-than greater-or-equal less-or-equal x x x x x x logical_and logical_or logical_not logical conjunction logical disjunction logical negation x && y x || y !x bit_and bit_or bit_xor bit-wise and bit-wise or bit-wise xor x & y x | y) x ^ y) y y y y y == y != y > y < y >= y <= y • makes it possible to pass “operators” as function arguments, and invoke them using ordinary function call syntax transform(begin(v1), end(v1), begin(v2), back_inserter(v3), plus<int>{}); File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 294 Standard library function object class definitions (1) • std::plus is defined (default argument void is C++14) template<typename T = void> struct plus { constexpr T operator()(const T& lhs, const T& rhs) const { return lhs + rhs; } using first_argument_type = T; using second_argument_type = T; using result_type = T; }; – wrapper for operator+ – works for all types T having operator+ and copy construction – implicit specialization (T = void) is illegal! – explicit specialization for a specific type creates a simple instance with all T:s replaced with that type – plus<int> • unary function objects should have the following two nested type definitions, instead of those three above using argument_type = …; using result_type = …; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 295 Standard library function object class definitions (2) • explicit (standard library) specialization for std::plus<void> (C++14) template<> struct plus<void> { template <typename T, typename U> constexpr auto operator()(T&& lhs, U&& rhs) const -> decltype(std::forward<T>(lhs) + std::forward<U>(rhs)) { return std::forward<T>(lhs) + std::forward<U>(rhs); } typedef unspecified is_transparent; }; • parameter types and return types are deduced – arguments can be different, compatible types • member type is_transparent indicates that this is a transparent function object – accepts arguments of arbitrary types – uses perfect forwarding – avoids unnecessary copying and conversion when used in heterogeneous context, or with rvalue arguments string a = "Hello "; const char* b = "world"; cout << plus<>{}(a, b) << ’\n’; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 296 Lambda expressions Lambda expressions provide a quick way to create (simple) function objects at their point of use array<int, 9> a{ 7, -2, -8, 4, 3, -5, 9, -1, 6 }; sort(begin(a), end(a), [](int x, int y) { return abs(x) < abs(y); }); • [] is the lambda introducer – introduces the declaration of a lambda expression – can contain zero or more lambda captures – [] only global and static entities can be referenced in the lambda – capture-less lambda expression – [&] will capture any name used from the reaching scope implicitly by reference – [=] will capture by value – [x] explicitly capture the object named x, as read only – [&x] will capture x by reference – [=, &x] default capture is by value, x is captured by reference – [this] will allow capturing members • () contains ordinary parameter declarations – can be left out if no parameters • {} is a compound statement • The return type is in the example above is implicitly deduced from the type of the returned value – it can be declared explicitly [](int x, int y) -> bool { return abs(x) < abs(y); } • there is more… File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 297 Closure objects • The evaluation of a lambda expression creates a closure object – a prvalue temporary – behaves as a function object • closure types are not specified but there are two easy ways to store closure objects – auto auto fun =[](int x, int y) { return abs(x) < abs(y); }; cout << fun(2, 1) << endl; – template std::function (introduced later) function<bool(int, int)> func = [](int x, int y) { return abs(x) < abs(y); }; cout << func(1, 2) << endl; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 298 Non-generic lambda expressions and closure types auto lambda = [](int a, int b) { return a < b; } bool (*fp)(int, int) = lambda; // pointer-to-function conversion allowed for capture-less lambdas The closure type for a non-generic lambda expression has a public operator() (1) • same parameter types and return type as the lambda expression • const if the lambda-expression’s parameter declaration clause is not followed by mutable Capture-less lambdas have a pointer to function conversion (2) • parameter types and return type are the same as for the function call operator • returns the address of a function (3) that, when invoked, has the same effect as invoking the function call operator class Closure { public: bool operator()(int a, int b) const { return a < b; } (1) private: static bool invoker_(int a, int b) { return a < b; } (3) using fptr_t = bool (*)(int, int); public: operator fptr_t() const { return &invoker_; } }; File: Standard-Function-Objects-OH-en (2) © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 299 Generic lambda expressions (C++14) auto lambda = [](const auto& a, const auto& b) { return a + b; }; • auto indicates a generic lambda parameter • closure operator() is a member template with one invented type template parameter for each occurrence of auto in the lambda struct Closure { template<typename T, typename U> auto operator()(const T& x, const U& y) const { return x + y; } }; – auto is used for the deduced return type of operator() • conversion from a capture-less generic lambda to an appropriate pointer-to-function is allowed long (*fp)(long, long) = lambda; – parameter types and also return type may differ File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 300 Generic lambda expressions and closure types (C++14) auto lambda = [](const auto& a, const auto& b) { return a + b; } Complete closure type for a capture-less lambda expression: struct Closure { template<typename T, typename U> auto operator()(const T& x, const U& y) const { return x + y; } private: template<typename T, typename U> static auto invoker_(const T& x, const U& y) { return x + y; } template<typename T, typename U> using fptr_t = decltype(invoker_(declval<T>{}, declval<U>{})) (*)(T, U); public: template<typename T, typename U> operator fptr_t<T, U>() const { return &invoker_; } }; • function template declval returns an rvalue reference (T&& and U&&, respectively) without referring to any object – references to (non-exciting) values of type T and U is used in the unevaluated call of invoker_ in decltype(…) – the return type of fptr_t is deduced this way File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 301 Generic lambda expressions for function parameter packs (C++14) The invented type template-parameter is a parameter pack if the corresponding parameter-declaration declares a function parameter pack. auto lambda = [](auto&&... fpp){ … }; // function parameter pack Closure type: struct Closure { public: template<typename... Args> auto operator()(Args&&... args) { … } // parameter pack … }; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 302 Function call syntax (1) There are three ways to invoke a function f on a class object of type T: f(x) Syntax #1: f is a normal function or function object and x is an object of type T x.f() Syntax #2: f is a member function and x is an object of type T or a reference to an object of type T p->f() Syntax #3: f is a member function and p is a pointer to an object of type T Suppose we have a unary function that can operate on objects of type T, and a container with elements of type T void fun(T& t); vector<T> v; • to apply fun to each object in the vector we can use the algorithm for_each for_each(begin(v), end(v), fun); // Fine, for_each uses call syntax #1 • if fun instead is a member of T and we try the following, it will not work for_each(begin(v), end(v), &T::fun); // Compile error, call syntax #2 required • the third variant would be if the container stores pointers to T, and fun is a member of T, which also will not work vector<T*> v; for_each(begin(v), end(v), &T::fun); File: Standard-Function-Objects-OH-en // Compile error, call syntax #3 required © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 303 Function call syntax (2) • the implementation of for_each shows why the passed function f cannot be a member function, unless adapted template<typename InputIterator, typename Function> Function for_each(InputIterator first, InputIterator last, Function f) { for (; first != last; ++first) f(*first); // syntax #1 return f; } – works with both ordinary functions and function objects, but not for calling member functions – all standard library algorithms use this normal function call syntax – to be able to call a member function we must adapt the member function call syntax to ordinary function call syntax x.memfun() –> f(x) x.memfun(y) –> f(x, y) • an ordinary function also need adaption, if a component require typedefs for argument type(s) and return type – for_each does not Before finding att how to solve this, lets find out what can be called… File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 304 Callable objects (1) Something that can be called as a function. • functions, function pointers, or function references void fun(int x) { cout << x << endl; } // function void (*fp)(int){ fun }; // function pointer (bound to fun above) void (&fr)(int){ fun }; // function reference (bound to fun above) fun(1); fp(2); fr(3); // 1 // 2 // 3 • objects implicitly converted to function pointer or to function reference struct Type { using Fun_Ptr = void (*)(int); operator Fun_Ptr() const { return fun; } }; // alt. void (&)(int) // conversion function – fun defined above Type obj; obj(4); // 4 File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 305 Callable objects (2) • function object struct Fun_Obj_Type { void operator()(int x) const { cout << x << endl; } }; Fun_Obj_Type obj; obj(6); // 6 • closure object – behaves as a function object auto f = [](int x){ cout << x << endl; }; f(7); File: Standard-Function-Objects-OH-en // 7 © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 306 Callable objects (3) • pointer to non-static member function struct Type { void mem_fun(int x) const { cout << x << endl; } }; auto pmf = &Type::mem_fun; // void (Type::*pmf)(int) const = &Type::mem_fun; Type obj; (obj.*pmf)(8); // 8 • to point to a static member function, an ordinary function pointer must be used struct Type { static void smem_fun(int x) { cout << x << endl; } }; auto fp = &Type::smem_fun; // void (*fp)(int) = &Type::smem_fun; Type obj; (fp)(9); File: Standard-Function-Objects-OH-en // 9 © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 307 Function call wrappers • negators – function call wrappers to negate the result from calling a predicate function – not1() helper function returning a function call wrapper for a unary predicate – not2() helper function returning a function call wrapper for a binary predicate • function argument binder – bind() returns a function call wrapper which binds a callable object and arguments • member function adaptor – mem_fn() returns a function call wrapper to call a member function using normal function call syntax • functions as first class citizens – function is a polymorphic function wrapper that can store, copy, and call arbitrary callable objects Note: These components are all defined using the new feature variadic template. File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 308 Negators (1) • not1() struct less_than_5 // a user defined unary predicate { constexpr bool operator()(int x) const { return x < 5; } typedef int argument_type; typedef bool return_type; }; vector<int> v{ 1, 8, 3, 6, 10, 7, 5, 9, 2, 4 }; cout << count_if(begin(v), end(v), not1(less_than_5{})) << endl; – the function object returned by not1() is applied to each element in v by transform – calls less_than_5{} and returns the result negated • not2() transform(begin(v1), end(v1), begin(v2), begin(v3), not2(std::less<int>{})); – the function object returned by not2() is applied to each pair of elements in v1 and v2 by transform – calls std::less<int>{} and returns the result negated File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 309 Negators (2) Utility function not1() takes a unary predicate Predicate and returns a function object of type unary_negate template<typename Predicate> unary_negate<Predicate> not1(const Predicate& pred) { return unary_negate<Predicate>(pred); } • Predicate must have nested type argument_type template<typename Predicate> class unary_negate { public: explicit unary_negate(const Predicate& x) : pred(x) {} bool operator()(const typename Predicate::argument_type& x) const { return !pred(x); } using argument_type = typename Predicate::argument_type; using result_type = bool; protected: Predicate pred; }; – defined by standard function objects – defined by std::function when wrapping a unary or binary function – defined by std::mem_fn when wrapping a unary or binary member function File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 310 Utility function std::bind #include <algorithm> #include <functional> #include <iostream> using namespace std; using namespace std::placeholders; vector<int> v{ 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 9 }; // not necessarily sorted • how many values in v are greater than 6? auto n = count_if(begin(v), end(v), bind(greater<int>{}, _1, 6)); • bind is given a binary predicate, greater<int>{}, and the arguments to be bound – the second parameter is bound to 6 – greater<int>()::operator(?, 6) – argument for the first parameter is to be supplied when count_if calls the unary predicate created by bind if (bind(greater<int>{}, _1, 6)(*it)) // effectively if (greater<int>{}(*it, 6)) – placeholder _1 refers to the first argument given in the call of the function call wrapper (*it) – in this case there is only one argument – the only valid placeholder is _1 File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 311 Utility function std::mem_fn class C { public: C(int i = 0) : value_(i) {} int times(int n) const { return n * value_; } operator int() const { return value_; } private: int value_; }; int a[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; vector<C> v(begin(a), end(a)); // initialize C objects with values from a transform(begin(v), end(v), begin(a), ostream_iterator<int>{cout," "}, mem_fn(&C::times)); • mem_fn covers all member function call variants – the call to transform would be the same if v was storing pointers to C vector<C*> v{ new C{1}, new C{2}, new C{3} }; • not restricted to member functions with just none or one parameter • nested types – result_type and argument_type are defined for member functions with no parameters – result_type, first_argument_type, and second_argument_type are defined for member functions with one parameter File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 312 Template std::function (1) • function wrapper class that can store, copy, and call arbitrary callable objects, such as – normal functions – function objects – closure objects (acts as function objects) – bind expressions • allow functions to be first-class objects, that is, can be – assigned – passed by value – returned by value – stored in data structures • exception bad_function_call is thrown by function::operator() when the function wrapper object has no target class bad_function_call : public std::exception { public: bad_function_call() noexcept; }; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 313 Template std::function (2) function<double(double)> fn; // no function bound – throws bad_function_call, if called fn = std::sinf; // normal function, signature float(float) cout << fn(3.14) << endl; // cos is overloaded in three version, for float, double, long double, type conversion required: fn = static_cast<double(*)(double)>(std::cos); cout << fn(3.14) << endl; fn = [](double d) -> double { return 2 * d; }; // closure object (lambda expression) cout << fn(3.14) << endl; function<bool(int)> pred{ bind(std::greater<int>(), _1, 10) }; // bind expression cout << boolalpha << pred(9) << ", " << pred(11) << endl; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 314 Template std::function (3) If instantiated for a unary or binary function: • have type definitions for result type and argument type(s) – for unary functions argument_type result_type – for binary functions first_argument_type second_argument_type result_type • expected by some components char* a[]{ "C++", "Ada", "Basic", "C", "C++", "Eiffel", "Java", "Python", "C++" } count_if(begin(a), end(a), not1(function<int(const char*)>{bind(strcmp, "C++", _1)})) – not1 require those types – bind does not supply – we can use function inbetween to supply the types – a lambda expression is much simpler to use in many cases, e.g in this case: count_if(begin(a), end(a), [](const char* s){ return !(strcmp("C++", s)); }) File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 315 Template std::function (4) Definition, parts of – just to give a hint on implementation: template<class> class function; // primary – undefined template <class R, class... ArgTypes> class function<R(ArgTypes...)> { public: ... function(); function(const function&); function(function&&); ... // result type, argument types // specialization for this function signature function& operator=(const function&); function& operator=(function&&); ... template<class F> function(F); ... // constructor taking function explicit operator bool() const noexcept; // true if *this has a target, otherwise false R operator()(ArgTypes...) const; // function call operator ... }; File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23) TDDD38 APiC++ Standard Library – Function objects and lambda expressions 316 Summing up: Containers – Iterators – Algorithms – Functions objects Designed for flexibility, extensibility, reuse and efficiency. • uniform interfaces – makes containers and iterators interchangeable – many algorithms can be applied to a variety of structures – makes learning and use easier • iterators is the “glue” that allow for combining components – algorithms operate on data through iterators – containers provide iterators – iterators can be bound to streams – ordinary pointers can in many cases be used where iterators are expected • function objects can be used for many different purposes – algorithms and containers can take a function object to modify their behaviour – function wrappers can be used to create more complicated operations from simple functions or function objects, e.g. – function call adaptors – reference wrapper – use lambda expressions for simple function objects • utilities for supporting rvalue references, move semantics, perfect forwarding, … • the template mechanism is heavily used, supports together with e.g. variadic templates – reusability, genericity, flexibility, efficiency File: Standard-Function-Objects-OH-en © 2015 Tommy Olsson, IDA, Linköpings universitet (2015-04-23)