44
Higher order programming Using C++ and boost

Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Embed Size (px)

Citation preview

Page 1: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Higher order programmingUsing C++ and boost

johant
En introduktion till några väldigt andvändbara bibliotek.Även C++, generic programming och STL.Bitvis mycket tekniska detaljer - avbryt och fråga!Tänkt som diskussionKom gärna förbi mig och fråga saker
Page 2: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

C++ concepts

// T must model MyFuncConcept

template<class T>

generic_function(T t)

{

t.MyFunc();

}

Page 3: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template 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

Page 4: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

C++ concepts

struct MyFuncClass { void MyFunc() {...} };

{

MyFuncClass mfc;

generic_function(mfc); // Compiles

int i;

generic_function(i); // Compilation error

}

Page 5: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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;

Page 6: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

C++ concepts• An assumption about a type parameter• Compilation error if assumption fails• Language support for concepts will be added in C++0Xtemplate <DefaultConstructible T> ...

Page 7: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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();...

}

Page 8: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Sidenote: boost::concept_check

• Provide easy to read compilation errors• Earlier compilation errors• Helps writing understandable code

Page 9: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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> >();

...

}

Page 10: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Higher order programming

Passing functions as values

Having values requires a type

Page 11: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

C++ function pointers• Unintuitive syntax• Casting between member function pointers problematic• Pointers to virtual functions problematic• Different compilers behave differentally

Page 12: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

C++ concept of a functorA class which defines operator()

struct SomeFunctor{void operator()() {...}

};

template <class F> void foo(F f){...f();...

}

Page 13: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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) {...}

};

Page 14: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Hand made functor examplesCan take various amounts of arguments

struct MyNullaryFunctor{void operator()();

};

struct MyUnaryFunctor{void operator()(int arg1);

};

Page 15: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Hand made functor examplesCan hold state

struct NullaryFunctor{NullaryFunctor(int state);void operator()();

private:int iState;

};

Some STL algorithms requires stateless functors

Page 16: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Hand made functor examples

Can return a value

struct SomePredicate

{

bool operator(int i)();

};

Page 17: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

STL algorithm exampletemplate <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

Page 18: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

STL functor examplenamespace

{

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());

}

Page 19: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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

Page 20: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::function examplevoid free_func(int x);

{

boost::function<void(int x)> callback = free_func;

callback(10);

}

Page 21: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::function examplestruct MyFunctor { void operator()(int x); };

{

boost::function<void(int x)> callback = MyFunctor();

callback(10);

}

Page 22: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::function examplestruct 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);

}

Page 23: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::function semantics {

boost::function<void(int x)> callback; // unitialized

...

if (callback) callback(10);

}

Page 24: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::function usage exampleclass OkCancelDialog

{

OkCancelDialog(const boost::function<void()>& onOk,

const boost::function<void()>& onCancel);

};

Page 25: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Recall from RAII presentation

prepare_something();

possibly_throwing_call_1();

possibly_throwing_call_2();

rollback_preparation();

rollback_call_1();

Page 26: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Recall from RAII presentationprepare_something();try{

possibly_throwing_call_1();try{

possibly_throwing_call_2();} catch (...){

rollback_call_1();rollback_preparation();throw;

}} catch (...){

rollback_preparation();throw;

}

Page 27: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Recall from RAII presentation• Error-prone to write• Difficult to read• Difficult to change• Poor scalability

Page 28: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Recall from RAII presentationclass ScopeGuard{ ScopeGuard(const boost::function<void()>& rollback) : mRollBack(rollback) {}

~ScopeGuard() {

if (mRollBack) mRollBack(); }

void Dismiss() {

mRollback = boost::function<void()>(); }

private:boost::function<void()> mRollback;

};

Page 29: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Recall from RAII presentationprepare_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();

Page 30: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Writing custom made functors• Is boring• Generates a lot of code• Takes some time

Page 31: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind

Generates unnamed functors from:• Function pointers• Member function pointers • Other functors

Meant to be used as unnamed temporaries

Page 32: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind examplevoid foo (int arg1, int arg2, int arg3)

{

std::cout << arg1 << ” ” << arg2 << ” ” << arg3 << std::endl;

}

{

boost::bind(foo, _1, _2, _3) (1, 2, 3);

boost::bind(foo, _3, _2, _1) (1, 2, 3);

boost::bind(foo, _1, _1, _1) (20);

boost::bind(foo, _3, _3, _3) (10, 20, 30);

boost::bind(foo, 1, 2, 3) ();

boost::bind(foo, 1, _1, 1) (1, 2, 3);

}

Page 33: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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;

};

Page 34: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind examplenamespace {

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));

}

Page 35: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind logical operators

{

std::vector<int> vec = ...;

unsigned int single_digits =

std::count_if(vec.begin(), vec.end(), _1>=0 && _1<=9);

}

Page 36: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind member functionsstruct 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));

}

Page 37: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind nested expressionsstd::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)) );

}

Page 38: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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;

};

Page 39: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind referencesvoid foo(const X& arg);

{

X x;

boost::bind(foo, boost::cref(x))();

}

Page 40: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

boost::bind and shared_ptrstruct X

{

void foo() {}

};

{

boost::shared_ptr<X> x;

boost::bind(&X::foo, x)();

}

Page 41: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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

Page 42: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Combining bind and function

function and bind both model the functor conceptBoth are compatible with other functors

void func(int arg1);

{

boost::function<void()> call = boost::bind(func, 1000);

}

Page 43: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

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));

}

Page 44: Higher order programming Using C++ and boost. C++ concepts // T must model MyFuncConcept template generic_function(T t) { t.MyFunc(); }

Boost lambdaSimilar to bind, larger and more advanced libraryPushes 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") )

);