【C++】std::bind与functional函数对象
2023-12-16 20:30:41
functional
std::bind
原型:
template< class R, class F, class... Args >
constexpr /* 未指定 */ bind( F&& f, Args&&... args );
函数模板 std::bind 生成 f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f
- f — 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)
- args ---- 要绑定的参数列表,未绑定参数会被命名空间 std::placeholders 的占位符 _1,_2, _3… 替换
使用示例
#include <functional>
#include <iostream>
#include <memory>
#include <random>
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo
{
void print_sum(int n1, int n2)
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main()
{
using namespace std::placeholders; // 对于 _1, _2, _3...
std::cout << "参数重排序和按引用传递:";
int n = 7;
// ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)
//std::cref返回需要被包装的到对象的左值引用,返回后面n的值
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001
// 进行到 f(2, 42, 1, n, 7) 的调用
std::cout << "嵌套 bind 子表达式共享占位符:";
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
std::cout << "绑定指向成员函数指针:";
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
std::cout << "绑定是指向成员函数指针的 mem_fn:";
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
f4(5);
std::cout << "绑定指向数据成员指针:";
auto f5 = std::bind(&Foo::data, _1);
std::cout << f5(foo) << '\n';
std::cout << "绑定是指向数据成员指针的 mem_fn:";
auto ptr_to_data = std::mem_fn(&Foo::data);
auto f6 = std::bind(ptr_to_data, _1);
std::cout << f6(foo) << '\n';
std::cout << "使用智能指针调用被引用对象的成员:";
std::cout << f6(std::make_shared<Foo>(foo)) << '\n'
<< f6(std::make_unique<Foo>(foo)) << '\n';
}
输出:
参数重排序和按引用传递:2 42 1 10 7
嵌套 bind 子表达式共享占位符:12 12 12 4 5
绑定指向成员函数指针:100
绑定是指向成员函数指针的 mem_fn:100
绑定指向数据成员指针:10
绑定是指向数据成员指针的 mem_fn:10
使用智能指针调用被引用对象的成员:10
10
std::function
类模板 std::function 是通用多态函数包装器。 std::function 的实例能存储、复制及调用任何可复制构造的可调用目标——函数(通过其指针)、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针。
存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。
- 实际上时对函数指针的优化
typedef void(*ptr)(int,int)// 这里的ptr就是一个函数指针
|
|
|
V
std::function<void(int ,int)> func;
- 头文件
#include <functional>
类模板
template< class R, class... Args >
class function<R(Args...)>;
- R: 被调用函数的返回类型
- Args…:被调用函数的形参
成员函数
- 构造函数
从各种资源构造 std::function
- 析构函数
销毁 std::function 对象。若 std::function 非空,则亦销毁其目标。
- operator=
赋值新目标给 std::function 。
- 赋值 other 的目标副本,如同以执行 function(other).swap(*this);
- 移动 other 的目标到 *this 。 other 在有未指定值的合法状态。
- 舍弃当前目标。 *this 在调用后为空。
template< class F >
function& operator=( std::reference_wrapper<F> f ) noexcept;
- swap
交换 *this 与 other 存储的可调用对象。
- operator bool
检查是否包含了有效的目标
- operator()
调用其目标
- target_type
返回存储的函数的类型。
- target
返回指向存储的可调用函数目标的指针。
使用
#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum {
void operator()(int i) const
{
std::cout << i << '\n';
}
};
int main()
{
// 存储自由函数
std::function<void(int)> f_display = print_num;
f_display(-9);//-9
// 存储 lambda
std::function<void()> f_display_42 = []() { print_num(42); };
f_display_42();//42
// 存储到 std::bind 调用的结果
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();//31337
// 存储到成员函数的调用
std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
const Foo foo(314159);//创建FOO对象
f_add_display(foo, 1);//314160
f_add_display(314159, 1);//314160
// 存储到数据成员访问器的调用
std::function<int(Foo const&)> f_num = &Foo::num_;
std::cout << "num_: " << f_num(foo) << '\n'; //num_: 314159
// 存储到成员函数及对象的调用
using std::placeholders::_1;
std::function<void(int)> f_add_display2 = std::bind( &Foo::print_add, foo, _1 );
f_add_display2(2);//314161
// 存储到成员函数和对象指针的调用
std::function<void(int)> f_add_display3 = std::bind( &Foo::print_add, &foo, _1 );
f_add_display3(3);//314162
// 存储到函数对象(仿函数)的调用
std::function<void(int)> f_display_obj = PrintNum();
f_display_obj(18);//18
//递归使用
std::function<int(int)> factorial = [&](int i) -> int{
if(i == 1)return 1;
return i * factorial(i - 1);
};
for (int i{5}; i != 8; ++i) { std::cout << i << "! = " << factorial(i) << "; "; }
}
其他:
#include <functional>
#include <iostream>
#include <string>
int f(int, int) { return 1; }
int g(int, int) { return 2; }
void test(std::function<int(int, int)> const& arg)
{
int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>();
if (ptr && *ptr == f)
std::cout << "it is the function f\n";
if (ptr && *ptr == g)
std::cout << "it is the function g\n";
}
int main()
{
test(std::function<int(int, int)>(f));
test(std::function<int(int, int)>(g));
std::function<int(int,int)> fn1(f),
fn2([](int a , int b) {return a+b;});
std::cout << fn1.target_type().name() << '\n'
<< fn2.target_type().name() << '\n';
}
输出结果:
it is the function f
it is the function g
PFiiiE
Z4mainEUliiE_
推导指引(C++17 起)
#include <functional>
int func(double) { return 0; }
int main() {
std::function f{func}; // 指引 #1 推导 function<int(double)>
int i = 5;
std::function g = [&](double) { return i; }; // 指引 #2 推导 function<int(double)>
}
文章来源:https://blog.csdn.net/qq_60755751/article/details/135036472
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!