Higher order programming Using C++ and boost C++ concepts // T must model MyFuncConcept template<class T> generic_function(T t) { t.MyFunc(); } C++ concepts T is a model of MyFuncConcept if T has a member function called MyFunc which takes no arguments C++ concepts struct MyFuncClass { void MyFunc() {...} }; { MyFuncClass mfc; generic_function(mfc); // Compiles int i; generic_function(i); // Compilation error } C++ example concepts Concept Assumed valid statment Default constructible T t; Copyable T t2(t1); Assignable t1 = t2; Convertible to OtherType static_cast<OtherType>(t); Output streamable stream << t; C++ concepts • An assumption about a type parameter • Compilation error if assumption fails • Language support for concepts will be added in C++0X template <DefaultConstructible T> ... Polymorphism through concepts Compile-time polymorphism through ”impicit interfaces” template<class T> void foo(T& t) { ... t.bar(); ... } Run-time polymorphism through explicit interfaces class FooType { virtual void bar() = 0; }; void foo(FooType& t) { ... t.bar(); ... } Sidenote: boost::concept_check • Provide easy to read compilation errors • Earlier compilation errors • Helps writing understandable code boost::concept_check example template <class RandomAccessIter> void stable_sort(RandomAccessIter first, RandomAccessIter last) { using namespace boost; function_requires< RandomAccessIteratorConcept<RandomAccessIter> >(); typedef typename std::iterator_traits<RandomAccessIter>::value_type value_type; function_requires< LessThanComparableConcept<value_type> >(); ... } Higher order programming Passing functions as values Having values requires a type C++ function pointers • • • • Unintuitive syntax Casting between member function pointers problematic Pointers to virtual functions problematic Different compilers behave differentally C++ concept of a functor A class which defines operator() struct SomeFunctor { void operator()() {...} }; template <class F> void foo(F f) { ... f(); ... } C++ concept of a functor Some STL algorithms also require internal typedefs for return_type, first_argument_type, second_argument_type struct SomeFunctor { typedef bool return_type; typedef int first_argument_type; bool operator()(int x) {...} }; Hand made functor examples Can take various amounts of arguments struct MyNullaryFunctor { void operator()(); }; struct MyUnaryFunctor { void operator()(int arg1); }; Hand made functor examples Can hold state struct NullaryFunctor { NullaryFunctor(int state); void operator()(); private: int iState; }; Some STL algorithms requires stateless functors Hand made functor examples Can return a value struct SomePredicate { bool operator(int i)(); }; STL algorithm example template <class InputIterator, class Predicate> std::iterator_traits<InputIterator>::difference_type std::count_if(InputIterator first, InputIterator last, Predicate pred) • InputIterator is a model of the Input Iterator concept • Predicate is a model of the Predicate concept • InputIterator's value type is convertible to Predicate's argument type STL functor example namespace { struct MyPredicate { bool operator()(int i) const { return i>=0 && i<=9; } }; } { std::vector<int> vec = ...; unsigned int single_digits = std::count_if(vec.begin(), vec.end(), MyPredicate()); } boost::function Generalized callback through functors • Compatible with free functions, member functions and other functors • Abstracts away callback type • Intuitive semantics • Easy to read syntax boost::function example void free_func(int x); { boost::function<void(int x)> callback = free_func; callback(10); } boost::function example struct MyFunctor { void operator()(int x); }; { boost::function<void(int x)> callback = MyFunctor(); callback(10); } boost::function example struct MyClass { void member_func(int x); }; { // Need an instance to call a member function variable boost::function<void(MyClass*, int x)> callback = &MyClass::member_func; MyClass my_class; callback(&my_class, 10); } boost::function semantics { boost::function<void(int x)> callback; // unitialized ... if (callback) callback(10); } boost::function usage example class OkCancelDialog { OkCancelDialog(const boost::function<void()>& onOk, const boost::function<void()>& onCancel); }; Recall from RAII presentation prepare_something(); possibly_throwing_call_1(); possibly_throwing_call_2(); rollback_preparation(); rollback_call_1(); Recall from RAII presentation prepare_something(); try { possibly_throwing_call_1(); try { possibly_throwing_call_2(); } catch (...) { rollback_call_1(); rollback_preparation(); throw; } } catch (...) { rollback_preparation(); throw; } Recall from RAII presentation • • • • Error-prone to write Difficult to read Difficult to change Poor scalability Recall from RAII presentation class ScopeGuard { ScopeGuard(const boost::function<void()>& rollback) : mRollBack(rollback) {} ~ScopeGuard() { if (mRollBack) mRollBack(); } void Dismiss() { mRollback = boost::function<void()>(); } private: boost::function<void()> mRollback; }; Recall from RAII presentation prepare_something(); ScopeGuard preparation_guard(rollback_preparation); possibly_throwing_call_1(); ScopeGuard call_1_guard(rollback_call_1); possibly_throwing_call_2(); // Commit preparation_guard.Dismiss(); call_1_guard.Dismiss(); Writing custom made functors • Is boring • Generates a lot of code • Takes some time boost::bind Generates unnamed functors from: • Function pointers • Member function pointers • Other functors Meant to be used as unnamed temporaries boost::bind example void foo (int arg1, int arg2, int arg3) { std::cout << arg1 << ” ” << arg2 << ” ” << arg3 << std::endl; } { boost::bind(foo, boost::bind(foo, boost::bind(foo, boost::bind(foo, boost::bind(foo, boost::bind(foo, } _1, _2, _3) (1, 2, 3); _3, _2, _1) (1, 2, 3); _1, _1, _1) (20); _3, _3, _3) (10, 20, 30); 1, 2, 3) (); 1, _1, 1) (1, 2, 3); boost::bind, what’s happening? void foo (int arg1, int arg2, int arg3); boost::bind(foo, 10, _1, 30); What’s the return type of the bind expression? struct some_super_strange_type_with_loads_of_templates { void operator(int x) { foo(iArg1, x, iArg3); } int iArg1, iArg3; }; boost::bind example namespace { bool my_pred (int i) { return i>=0 && i<=9; } } { std::vector<int> vec = ...; unsigned int single_digits = std::count_if(vec.begin(), vec.end(), boost::bind(my_pred, _1)); } boost::bind logical operators { std::vector<int> vec = ...; unsigned int single_digits = std::count_if(vec.begin(), vec.end(), _1>=0 && _1<=9); } boost::bind member functions struct X { void SomeFunc(int arg1, int arg2); }; { std::vector<X> vec; std::for_each(vec.begin(), vec.end(), boost::bind(&X::SomeFunc, _1, 1, 2)); } boost::bind nested expressions std::string f(std::string const & x) { return "f(" + x + ")"; } std::string g(std::string const & x) { return "g(" + x + ")"; } std::string h(std::string const & x, std::string const & y) { return "h(" + x + ", " + y + ")"; } std::string k() { return "k()"; } template<class F> void test(F f) { std::cout << f("x", "y") << '\n'; } { using namespace boost; test( bind(f, bind(g, _1)) ); test( bind(f, bind(h, _1, _2)) ); test( bind(h, bind(f, _1), bind(g, _1)) ); test( bind(h, bind(f, _1), bind(g, _2)) ); test( bind(f, bind(k)) ); } boost::bind semantics Bound values are stored by value! struct some_super_strange_type_with_loads_of_templates { void operator(int x) { foo(iArg1, x, iArg3); } int iArg1, iArg3; }; boost::bind references void foo(const X& arg); { X x; boost::bind(foo, boost::cref(x))(); } boost::bind and shared_ptr struct X { void foo() {} }; { boost::shared_ptr<X> x; boost::bind(&X::foo, x)(); } bind&function usage Bind • • • • Pass as unnamed temporaries for templated functions Bind arguments as state Specifically bind instances to member functions Reorder arguments Function • • • • Pass as arguments for non-templated functions Abstracts away function type Store as non-templated variables Can be uninitialized Combining bind and function function and bind both model the functor concept Both are compatible with other functors void func(int arg1); { boost::function<void()> call = boost::bind(func, 1000); } Combining bind and function // Non-templated higher order function void register_callback(boost::function<void()> callback); void my_callback(int source); { register_callback(boost::bind(&my_callback, 10)); } Boost lambda Similar to bind, larger and more advanced library Pushes the limits of the C++ language using namespace boost; std::vector<int> v = ...; std::for_each(v.begin(), v.end(), if_(_1 % 2 == 0)[ cout << _1 ]); int a[5][10]; int i; std::for_each(a, a+5, for_loop(var(i)=0, var(i)<10, ++var(i), _1[var(i)] += 1)); std::for_each(v.begin(), v.end(), ( switch_statement( _1, case_statement<0>(std::cout << constant("zero")), case_statement<1>(std::cout << constant("one")), default_statement(cout << constant("other: ") << _1) ), cout << constant("\n") ) );