C++20 之std::function()作為函式輸入輸出引數 tcy
阿新 • • 發佈:2021-01-27
技術標籤:C/C++
1.1.說明: C語言用函式指標來作為函式引數實現回撥函式的機制 C++中function是通用的多型函式封裝器,它的例項可以儲存、複製以及呼叫任何可以呼叫的目標 (包括函式,仿函式,函式指標,bind表示式,lambda閉包) 1.2.function作為函式引數: int registerCallBack(std::function<int(*)(int,int)> f); //基於傳值 int registerCallBack(const std::function<int(*)(int,int)>& f); //基於引用 int registerCallBack(const std::function<int(*)(int,int)>&& f);//目前沒有發現有什麼用 std::function<int(*)(int,int)> fun(); std::function<int(*)(int,int)>& fun(); //目前沒有發現有什麼用 std::function<int(*)(int,int)>&& fun();//目前沒有發現有什麼用
1.3.類的成員函式作為函式入參 //類成員函式預設有隱藏this指標,不能直接作為函式入參 struct A{ typedef std::function<void(int i)> callback_t; void foo(callback_t func){f = std::move(func);}//效率更高 private: callback_t f; }; //類B需註冊一成員函式作為回撥函式到A中 //用bind實現(顯式傳遞B的this指標作為第一個引數給回撥函式) struct B{B(A& a){ a.foo(std::bind(&B::handle, this, std::placeholders::_1));}}; //使用lambda表示式實現 struct B{B(A& a){ a.foo([this](int i){B::handle(i);});
2.例項:
#include <iostream> #include <functional> #include<cassert> using namespace std; //傳引用: int foo(int x, int y, const std::function<int(int, int)>& f){ return f(x, y);} //傳值: int bar(int x, int y, std::function<int(int, int)> f){ return f(x, y);} //傳引用: int fun(int x, int y, std::function<int(int, int)>&& f) { auto tmp = std::move(f);return tmp(x, y);}//傳入的是function物件,即使傳入仿函式move也無法移動
int add(int x, int y) { return x + y; }
struct Add {int operator()(int x, int y) { return x + y ; }};
//1.1.function物件用作函式引數:
void test_functon() {
//1.1.函式指標-普通用法:
using pfunc = int(*)(int, int);//typedef int(*pfunc)(int, int);等價
pfunc p = add;assert(p(1, 2) == add(1, 2));
//1.2.函式指標:-輸入引數
assert(foo(1, 2, p) == add(1,2));
//2.函式:-輸入引數
assert(foo(1, 2, add) == add(1, 2));
//3.仿函式:-輸入引數
Add add_obj;
assert(foo(1, 2, add_obj) == add(1, 2));
//4.lambda:-輸入引數
auto add_lambda = [](int x, int y)->int {return x + y; };
assert(foo(1, 2, add_lambda) == add(1, 2));
}
//1.2.測試引數傳值傳引用的區別
//對於函式,labmda,函式指標無區別,但對於有成員變數的仿函式則有區別
struct Add_Inc {
int operator()(int x, int y) { *z = *z + 1; return x + y; }
shared_ptr<int> z{ make_shared<int>(10) };
};
void test_fun_input_parameter() {
assert(foo(1, 2, add) == add(1, 2)); //傳引用
assert(bar(1, 2, add) == add(1, 2)); //傳值
Add add_obj;
assert(fun(1, 2, add_obj) == add(1, 2));//傳move,將仿函式包裝成函式物件fun中move無效
assert(fun(1, 2, add) == add(1, 2)); //傳move,普通函式fun中move無效
Add_Inc obj;
Add_Inc add_inc;
assert(*add_inc.z == 10);
//當仿函式Add_Inc成員變數z為智慧指標時無論引用傳值都將修改變數z的值;
//當仿函式Add_Inc成員變數z為int z{10}時無論引用傳值都不修改變數z的值;
assert(foo(1, 2, add_inc) == add(1, 2)); assert(*add_inc.z == 11);
assert(bar(1, 2, add_inc) == add(1, 2)); assert(*add_inc.z == 12);
assert(fun(1, 2, add_inc) == add(1, 2)); assert(*add_inc.z == 13);
}
//1.3.function物件為函式輸出引數
std::function<int(int, int)> add_fun(int x, int y) {
auto add = [=](int x1,int y1)->int {return x1 + y1 + x + y; };
return add;
}
std::function<int(int, int)> add_fun_err(int x, int y) {
auto add = [&x,&y](int x1, int y1)->int {return x1 + y1 + x + y; };
return add;
}
void test_fun_output_parameter() {
auto f = add_fun(1, 2);
assert(f(3, 4) == 1+2+3+4);
auto f1 = add_fun_err(1, 2);//結果不是你所期望的
assert(f1(3, 4) == 3 + 4 + 3 + 4);
}
//2.類成員函式作為引數:
class A {
typedef std::function<int(int, int)> callback_t;
public:
int add(int x, int y) { return f_add(x, y); }
void registFunc(callback_t pFunc) { f_add = std::move(pFunc); }
private:
callback_t f_add;
};
class B {
public:
int add(int x, int y) { return x + y; }
B(A& a) { a.registFunc([this](int x, int y) {return B::add(x, y); }); }
};
void test_class() {
A a;
B b(a);
assert(b.add(1, 2)==3);//直接使用類成員函式
assert(a.add(1, 2) == 3);//不夠直觀
//將類例項物件做一個簡單的包裝,比較容易理解
auto b_div = [&b](int x, int y) {return b.add(x, y); };
assert(bar(1, 2, b_div)==3);
}
int main() {
test_functon();
test_fun_input_parameter();
test_fun_output_parameter();
test_class();
}