Higher order programming Using C and boost C
Higher order programming Using C++ and boost
C++ concepts // T must model My. Func. Concept template<class T> generic_function(T t) { t. My. Func(); }
C++ concepts T is a model of My. Func. Concept if T has a member function called My. Func which takes no arguments
C++ concepts struct My. Func. Class { void My. Func() {. . . } }; { My. Func. Class 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 t 2(t 1); Assignable t 1 = t 2; Convertible to Other. Type static_cast<Other. Type>(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++0 X template <Default. Constructible 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 Foo. Type { virtual void bar() = 0; }; void foo(Foo. Type& 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 Random. Access. Iter> void stable_sort(Random. Access. Iter first, Random. Access. Iter last) { using namespace boost; function_requires< Random. Access. Iterator. Concept<Random. Access. Iter> >(); typedef typename std: : iterator_traits<Random. Access. Iter>: : value_type; function_requires< Less. Than. Comparable. Concept<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 Some. Functor { 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 Some. Functor { typedef bool return_type; typedef int first_argument_type; bool operator()(int x) {. . . } };
Hand made functor examples Can take various amounts of arguments struct My. Nullary. Functor { void operator()(); }; struct My. Unary. Functor { void operator()(int arg 1); };
Hand made functor examples Can hold state struct Nullary. Functor { Nullary. Functor(int state); void operator()(); private: int i. State; }; Some STL algorithms requires stateless functors
Hand made functor examples Can return a value struct Some. Predicate { bool operator(int i)(); };
STL algorithm example template <class Input. Iterator, class Predicate> std: : iterator_traits<Input. Iterator>: : difference_type std: : count_if(Input. Iterator first, Input. Iterator last, Predicate pred) • Input. Iterator is a model of the Input Iterator concept • Predicate is a model of the Predicate concept • Input. Iterator's value type is convertible to Predicate's argument type
STL functor example namespace { struct My. Predicate { 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(), My. Predicate()); }
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 My. Functor { void operator()(int x); }; { boost: : function<void(int x)> callback = My. Functor(); callback(10); }
boost: : function example struct My. Class { void member_func(int x); }; { // Need an instance to call a member function variable boost: : function<void(My. Class*, int x)> callback = &My. Class: : member_func; My. Class 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 Ok. Cancel. Dialog { Ok. Cancel. Dialog(const boost: : function<void()>& on. Ok, const boost: : function<void()>& on. Cancel); };
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 Scope. Guard { Scope. Guard(const boost: : function<void()>& rollback) : m. Roll. Back(rollback) {} ~Scope. Guard() { if (m. Roll. Back) m. Roll. Back(); } void Dismiss() { m. Rollback = boost: : function<void()>(); } private: boost: : function<void()> m. Rollback; };
Recall from RAII presentation prepare_something(); Scope. Guard preparation_guard(rollback_preparation); possibly_throwing_call_1(); Scope. Guard 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 arg 1, int arg 2, int arg 3) { std: : cout << arg 1 << ” ” << arg 2 << ” ” << arg 3 << std: : endl; } { boost: : bind(foo, boost: : bind(foo, } _1, _2, _3) (1, 2, 3); _3, _2, _1) (1, 2, 3); _1, _1) (20); _3, _3) (10, 20, 30); 1, 2, 3) (); 1, _1, 1) (1, 2, 3);
boost: : bind, what’s happening? void foo (int arg 1, int arg 2, int arg 3); 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(i. Arg 1, x, i. Arg 3); } int i. Arg 1, i. Arg 3; };
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 Some. Func(int arg 1, int arg 2); }; { std: : vector<X> vec; std: : for_each(vec. begin(), vec. end(), boost: : bind(&X: : Some. Func, _1, 1, 2)); }
boost: : bind nested expressions std: : string { return std: : string f(std: : string const g(std: : string const h(std: : string const "h(" + x + ", " + y k() { return "k()"; & & & + } x) { return "f(" + x + ")"; } x) { return "g(" + x + ")"; } x, std: : string const & y) ")"; } 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, test( bind(h, bind(f, _1), test( bind(f, bind(k)) ); } ); _1, _2)) ); bind(g, _1)) ); bind(g, _2)) );
boost: : bind semantics Bound values are stored by value! struct some_super_strange_type_with_loads_of_templates { void operator(int x) { foo(i. Arg 1, x, i. Arg 3); } int i. Arg 1, i. Arg 3; };
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 and bind both model the functor concept Both are compatible with other functors void func(int arg 1); { 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") ) );
- Slides: 44