Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
53
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 52: std::function: To wrap any element that is callable

Section 52.1: Simple usage

#include <iostream> #include <functional>

std::function<void(int , const std::string&)> myFuncObj; void theFunc(int i, const std::string& s)

{

std::cout << s << ": " << i << std::endl;

}

int main(int argc, char *argv[])

{

myFuncObj = theFunc; myFuncObj(10, "hello world");

}

Section 52.2: std::function used with std::bind

Think about a situation where we need to callback a function with arguments. std::function used with std::bind gives a very powerful design construct as shown below.

class A

{

public:

std::function<void(int, const std::string&)> m_CbFunc = nullptr; void foo()

{

if (m_CbFunc)

{

m_CbFunc(100, "event fired");

}

}

};

class B

{

public: B()

{

auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);

anObjA.m_CbFunc = aFunc;

}

void eventHandler(int i, const std::string& s)

{

std::cout << s << ": " << i << std::endl;

}

void DoSomethingOnA()

{

anObjA.foo();

}

A anObjA;

};

GoalKicker.com – C++ Notes for Professionals

299

int main(int argc, char *argv[])

{

B anObjB; anObjB.DoSomethingOnA();

}

Section 52.3: Binding std::function to a di erent callable types

/*

*This example show some ways of using std::function to call

*a) C-like function

*b) class-member function

*c) operator()

*d) lambda function

*

*Function call can be made:

*a) with right arguments

*b) argumens with different order, types and count

*/

#include <iostream> #include <functional> #include <iostream> #include <vector>

using std::cout; using std::endl;

using namespace std::placeholders;

// simple function to be called

double foo_fn(int x, float y, double z)

{

double res = x + y + z;

std::cout << "foo_fn called with arguments: "

<<x << ", " << y << ", " << z

<<" result is : " << res

<<std::endl;

return res;

}

// structure with member function to call struct foo_struct

{

// member function to call

double foo_fn(int x, float y, double z)

{

double res = x + y + z;

std::cout << "foo_struct::foo_fn called with arguments: "

<<x << ", " << y << ", " << z

<<" result is : " << res

<<std::endl;

return res;

}

//this member function has different signature - but it can be used too

//please not that argument order is changed too

double foo_fn_4(int x, double z, float y, long xx)

{

double res = x + y + z + xx;

std::cout << "foo_struct::foo_fn_4 called with arguments: "

GoalKicker.com – C++ Notes for Professionals

300

<<x << ", " << z << ", " << y << ", " << xx

<<" result is : " << res

<<std::endl;

return res;

}

// overloaded operator() makes whole object to be callable double operator()(int x, float y, double z)

{

double res = x + y + z;

std::cout << "foo_struct::operator() called with arguments: "

<<x << ", " << y << ", " << z

<<" result is : " << res

<<std::endl;

return res;

}

};

int main(void)

{

// typedefs

using function_type = std::function<double(int, float, double)>;

//foo_struct instance foo_struct fs;

//here we will store all binded functions std::vector<function_type> bindings;

//var #1 - you can use simple function function_type var1 = foo_fn; bindings.push_back(var1);

//var #2 - you can use member function

function_type var2 = std::bind(&foo_struct::foo_fn, fs, _1, _2, _3); bindings.push_back(var2);

//var #3 - you can use member function with different signature

//foo_fn_4 has different count of arguments and types

function_type var3 = std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l); bindings.push_back(var3);

//var #4 - you can use object with overloaded operator() function_type var4 = fs;

bindings.push_back(var4);

//var #5 - you can use lambda function

function_type var5 = [](int x, float y, double z)

{

double res = x + y + z;

std::cout << "lambda called with arguments: "

<<x << ", " << y << ", " << z

<<" result is : " << res

<<std::endl;

return res;

}; bindings.push_back(var5);

std::cout << "Test stored functions with arguments: x = 1, y = 2, z = 3" << std::endl;

for (auto f : bindings)

GoalKicker.com – C++ Notes for Professionals

301

f(1, 2, 3);

}

Live

Output:

Test stored functions with arguments: x = 1, y = 2, z = 3 foo_fn called with arguments: 1, 2, 3 result is : 6 foo_struct::foo_fn called with arguments: 1, 2, 3 result is : 6

foo_struct::foo_fn_4 called with arguments: 1, 3, 2, 0 result is : 6 foo_struct::operator() called with arguments: 1, 2, 3 result is : 6 lambda called with arguments: 1, 2, 3 result is : 6

Section 52.4: Storing function arguments in std::tuple

Some programs need so store arguments for future calling of some function. This example shows how to call any function with arguments stored in std::tuple

#include <iostream> #include <functional> #include <tuple> #include <iostream>

// simple function to be called

double foo_fn(int x, float y, double z)

{

double res = x + y + z;

std::cout << "foo_fn called. x = " << x << " y = " << y << " z = " << z << " res=" << res;

return res;

}

//helpers for tuple unrolling template<int ...> struct seq {};

template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {}; template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };

//invocation helper

template<typename FN, typename P, int ...S>

double call_fn_internal(const FN& fn, const P& params, const seq<S...>)

{

return fn(std::get<S>(params) ...);

}

// call function with arguments stored in std::tuple template<typename Ret, typename ...Args>

Ret call_fn(const std::function<Ret(Args...)>& fn, const std::tuple<Args...>& params)

{

return call_fn_internal(fn, params, typename gens<sizeof...(Args)>::type());

}

int main(void)

{

// arguments

std::tuple<int, float, double> t = std::make_tuple(1, 5, 10); // function to call

GoalKicker.com – C++ Notes for Professionals

302