C++11中std::bind的使用

本文详细介绍了C++标准库中的std::bind函数的使用方法。std::bind可以用来绑定函数的部分参数,生成新的可调用对象。文章通过多个示例展示了如何使用std::bind进行参数绑定、调整参数顺序等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

std::bind函数是用来绑定函数调用的某些参数的。std::bind它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体。它绑定的参数的个数不受限制,绑定的具体哪些参数也不受限制,由用户指定

std::bind:(1)、将函数、成员函数和闭包转成function函数对象;(2)、将多元(n>1)函数转成一元函数或者(n-1)元函数。

std::bind本身是一种延迟计算的思想,它本身可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数。无法使用std::bind绑定一个重载函数的参数,必须显式地指出需要绑定的重载函数的版本。成员函数区别于普通函数的一个特殊之处在于,其第一个参数必须是该类型的一个对象(或对象的指针或引用)。

std::bind接受一个函数(或者函数对象,或者任何你可以通过"(…)"符号调用的事物),生成一个其有某一个或多个函数参数被”绑定”或重新组织的函数对象。绑定的参数将会以值传递的方式传递给具体函数,占位符将会以引用传递。

std::bind需要注意事项:

(1)、bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的;

(2)、对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的;

(3)、bind的返回值是可调用实体,可以直接赋给std::function对象;

(4)、对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的;

(5)、类的this可以通过对象或者指针来绑定。

std::bind: Each argument may either be bound to a value or be a placeholder:

(1)、If bound to a value, calling the returned function object will always use that value as argument;

(2)、If a placeholder, calling the returned function object forwards an argument passed to the call (the one whose order number is specified by the placeholder).

std::bind receives a pointer to a function (it also can be a lambda expression or a functor) and receives a list of parameters that pass it to the function. As result, bind returns a new function object with a different prototype because all the parameters of the function were already specified.

A placeholder is an object that specifies the number of parameter in the bound function that will be used to enter this parameter.

std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "bind.hpp"
#include <iostream>
#include <string>
#include <functional> // std::bind
#include <random>
#include <memory>
#include <algorithm>

//////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/utility/functional/bind
static void f(int n1, int n2, int n3, const int& n4, int n5)
{
	std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}

static int g(int n1)
{
	return n1;
}

struct Foo_bind {
	void print_sum(int n1, int n2)
	{
		std::cout << n1 + n2 << '\n';
	}
	int data = 10;
};

int test_bind1()
{
	using namespace std::placeholders;  // for _1, _2, _3...

	// demonstrates argument reordering and pass-by-reference
	int n = 7;
	// (_1 and _2 are from std::placeholders, and represent future
	// arguments that will be passed to f1)
	auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
	n = 10;
	f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
	// makes a call to f(2, 1, 42, n, 7)

	// nested bind subexpressions share the placeholders
	auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
	f2(10, 11, 12);

	// common use case: binding a RNG with a distribution
	std::default_random_engine e;
	std::uniform_int_distribution<> d(0, 10);
	std::function<int()> rnd = std::bind(d, e); // a copy of e is stored in rnd
	for (int n = 0; n<10; ++n)
		std::cout << rnd() << ' ';
	std::cout << '\n';

	// bind to a pointer to member function
	Foo_bind foo;
	auto f3 = std::bind(&Foo_bind::print_sum, &foo, 95, _1);
	f3(5);

	// bind to a pointer to data member
	auto f4 = std::bind(&Foo_bind::data, _1);
	std::cout << f4(foo) << '\n';

	// smart pointers can be used to call members of the referenced objects, too
	//std::cout << f4(std::make_shared<Foo_bind>(foo)) << '\n'
	//	<< f4(std::make_unique<Foo_bind>(foo)) << '\n';

	return 0;
}

///////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/functional/bind/
// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide(double x, double y) { return x / y; }

struct MyPair {
	double a, b;
	double multiply() { return a*b; }
};

int test_bind2()
{
	using namespace std::placeholders;    // adds visibility of _1, _2, _3,...

	// binding functions:
	auto fn_five = std::bind(my_divide, 10, 2);               // returns 10/2
	std::cout << fn_five() << '\n';                          // 5

	auto fn_half = std::bind(my_divide, _1, 2);               // returns x/2
	std::cout << fn_half(10) << '\n';                        // 5

	auto fn_invert = std::bind(my_divide, _2, _1);            // returns y/x
	std::cout << fn_invert(10, 2) << '\n';                    // 0.2

	auto fn_rounding = std::bind<int>(my_divide, _1, _2);     // returns int(x/y)
	std::cout << fn_rounding(10, 3) << '\n';                  // 3

	MyPair ten_two{ 10, 2 };

	// binding members:
	auto bound_member_fn = std::bind(&MyPair::multiply, _1); // returns x.multiply()
	std::cout << bound_member_fn(ten_two) << '\n';           // 20

	auto bound_member_data = std::bind(&MyPair::a, ten_two); // returns ten_two.a
	std::cout << bound_member_data() << '\n';                // 10

	return 0;
}

/////////////////////////////////////////////////
// reference: https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/
static void show(const std::string& a, const std::string& b, const std::string& c)
{
	std::cout << a << "; " << b << "; " << c << std::endl;
}

int test_bind3()
{
	using namespace std::placeholders;

	// Thanks to the placeholders, you can change the order of the arguments passed as parameters to a bound function.
	auto x = bind(show, _1, _2, _3);
	auto y = bind(show, _3, _1, _2);
	auto z = bind(show, "hello", _2, _1);

	x("one", "two", "three");
	y("one", "two", "three");
	z("one", "two");

	return 0;
}

/////////////////////////////////////////////////////
// reference: http://stackoverflow.com/questions/22422147/why-is-stdbind-not-working-without-placeholders-in-this-example-member-functi
static void f_(int a, int b, int c)
{
	fprintf(stdout, "a = %d, b = %d, c = %d\n", a, b, c);
}

struct foo_bind
{
	void f() const { fprintf(stdout, "foo_bind\n"); };
};

int test_bind4()
{
	using namespace std::placeholders;

	// The first parameter of std::bind() is the function to be called, and the rest are the arguments of the call.
	std::function<void()> f_call = std::bind(f_, 1, 2, 3);
	f_call(); //Equivalent to f_(1,2,3)

	// If you need to specify that some parameters have to be specified at the call point,
	// you have to use placeholders to represent that parameters
	std::function<void(int, int, int)> f_call2 = std::bind(f_, _1, _2, _3);
	f_call2(1, 2, 3); //Same as f_(1,2,3)

	// Note that the numbers of the placeholders specify the number of the parameter at the call point.
	// The first parameter of the call point is identified by _1, the second by _2, and so on.
	// This could be used to specify parameters in different ways, reordering the parameters of a function call, etc.
	std::function<void(int, int)> f_call3 = std::bind(f_, _1, 2, _2);
	f_call3(1, 3); //Equivalent to f_( 1 , 2 , 3 );

	std::function<void(int, int, int)> reordered_call = std::bind(f_, _3, _2, _1);
	reordered_call(3, 2, 1); //Same as f_( 1 , 2 , 3 );

	// std::bind() could be used to bind a member function to the object used to call it
	foo_bind myfoo;
	std::function<void()> f = std::bind(&foo_bind::f, std::cref(myfoo));
	f();

	return 0;
}

/////////////////////////////////////////////////
// reference: https://msdn.microsoft.com/en-us/library/bb982702.aspx
static void square(double x)
{
	std::cout << x << "^2 == " << x * x << std::endl;
}

static void product(double x, double y)
{
	std::cout << x << "*" << y << " == " << x * y << std::endl;
}

int test_bind5()
{
	using namespace std::placeholders;

	double arg[] = { 1, 2, 3 };

	std::for_each(&arg[0], arg + 3, square);
	std::cout << std::endl;

	std::for_each(&arg[0], arg + 3, std::bind(product, _1, 2));
	std::cout << std::endl;

	std::for_each(&arg[0], arg + 3, std::bind(square, _1));

	return (0);
}

GitHubhttps://github.com/fengbingchun/Messy_Test

<think>首先,用户的问题是:“我想了解C++bind函数的用法或解决相关问题请问C++bind函数使用方法示例”。这直接问bind函数的用法、方法和示例。系统级指令:我必须使用中文回答,确保行内数学表达式用$...$,独立公式用$$...$$并单独成段。LaTeX语法正确。生成相关问题。在引用段落末尾自然地添加引用标识,如[^1]。引用内容:用户提供了几个引用,但提到了“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。”不过,这是第一次交互,所以没有上一次的问题。引用是关于bind和lambda的,所以我会参考它们。引用[1]:boost::lambda的bind函数用法。引用[2]:std::bind使用,绑定成员函数。引用[3]:std::bind的基本用法。引用[4]:Lambda表达式的示例。由于用户问的是bind函数,我应该专注于C++标准库的std::bind,引用[2]和[3]直接相关。引用[1]是关于boost::lambda::bind的,但用户可能在问标准bind,所以我会以std::bind为主。回答结构:系统要求结构清晰,帮助用户逐步解决问题。真实可靠。大纲回答:1.**引入bind函数**:简要解释std::bind是什么、为什么使用它。2.**基本用法**:解释bind的工作原理。3.**示例代码**:提供几个示例,包括绑定自由函数、成员函数、改变参数顺序、绑定对象等。4.**与lambda的比较**:或许简要提到bind和lambda的区别,因为引用中有lambda。5.**常见问题**:解决可能的问题。6.**生成相关问题**:在最后添加相关问题。引用标识:在引用的段落末尾添加引用标识。例如,如果我从引用[2]或[3]获取信息,就在那里添加[^2]或[^3]。但由于用户说“上述引用仅供参考”,我应该尽量基于知识,确保真实,如果需要引用特定段落时再添加。确保中文回答。关键点:-std::bind用于将函数或成员函数绑定到参数,创建新的可调用对象。-用法示例:-绑定自由函数:类似引用[3]的示例。-绑定成员函数:类似引用[2],需要绑定对象。-使用占位符(placeholders)如_1,_2等来延迟提供参数。-改变参数顺序。完整示例代码:需要在回复中包含代码块。系统要求代码用代码块形式,如示例中的```python```,但这里是C++,所以用```c++```。生成相关问题:在回答结束前,类似示例中的“§§相关问题§§”部分。写回答:-开头:介绍bind函数。-主体:逐步解释用法和示例。-代码:放入代码块。-结尾:添加相关问题。</think> 以下是关于C++中`std::bind`函数(也称为`bind`函数)的详细解答。`std::bind`是C++标准库中的函数模板(定义在`<functional>`头文件中),用于将函数或成员函数绑定到参数上,创建一个新的可调用对象(例如函数对象)。它的主要作用是**部分应用**函数,即可以预先固定部分参数、改变参数顺序,或延迟调用。这在回调、事件处理和高阶函数编程中非常实用[^3]。我将逐步解释其使用方法、注意事项,并提供多个示例代码,确保内容真实可靠(基于C++11及以后标准)。 ### 1. `std::bind`的基本概念 `std::bind`的语法如下: ```cpp auto bound_function = std::bind(target_function, arguments...); ``` - **target_function**: 要绑定的目标函数(自由函数、成员函数、函数对象)。 - **arguments...**: 要绑定的参数。可以是具体值或占位符(placeholders,如`std::placeholders::_1`、`_2`),其中占位符表示该参数在调用时动态传入。 - **返回值**: 返回一个新的可调用对象(类型为`std::function`或类似),调用`bound_function(args...)`时等价于`target_function(bound_arguments...)`。 为什么使用`std::bind`? - **部分应用**: 固定部分参数,减少重复代码。 - **改变参数顺序**: 调整参数的接收顺序。 - **成员函数绑定**: 需要绑定到具体对象。 - **兼容旧代码**: 比Lambda表达式更通用在复杂场景(但新代码中Lambda更推荐)。 数学上,部分应用对应于高阶函数在函数式编程中的概念[^3]。 ### 2. 使用方法与示例 以下是`std::bind`的常见用法。所有代码示例都使用C++11及以上标准,编译时确保启用`-std=c++11`或更高版本。我在代码中加入了中文注释方便理解。 #### 示例1: 绑定自由函数(固定所有参数) 固定自由函数的所有参数,创建一个无参数的可调用对象。类似引用[3]的示例。 ```cpp #include <iostream> #include <functional> // 必须包含此头文件 // 定义自由函数 void free_function(int a, int b) { std::cout << "Sum: " << a + b << std::endl; } int main() { // 绑定free_function的前两个参数为10和20,创建新函数对象 auto bound_function = std::bind(free_function, 10, 20); // 调用时无需传参数(所有参数已固定) bound_function(); // 输出: Sum: 30 return 0; } ``` - **解释**: `std::bind(free_function, 10, 20)`绑定后,`bound_function()`等价于`free_function(10, 20)`。 - **应用场景**: 需要缓存或延迟计算。 #### 示例2: 使用占位符(动态绑定部分参数) 绑定部分参数,其余参数在调用时提供。占位符`_1`表示第一个动态参数、`_2`表示第二个,依此类推。 ```cpp #include <iostream> #include <functional> void free_function(int a, int b) { std::cout << "Sum: " << a + b << std::endl; } int main() { // 绑定free_function: 第一个参数固定为10,第二个参数动态传入(使用占位符_1) auto bound_function = std::bind(free_function, 10, std::placeholders::_1); // 调用时传入动态参数(20对应占位符_1) bound_function(20); // 输出: Sum: 30 // 也可以绑定为动态顺序 auto reverse_function = std::bind(free_function, std::placeholders::_2, std::placeholders::_1); reverse_function(30, 10); // 输出: Sum: 40 (参数顺序被改变) return 0; } ``` - **解释**: `std::bind(free_function, 10, _1)`绑定后,`bound_function(20)`等价于`free_function(10, 20)`。`reverse_function`改变参数顺序。 - **占位符用法**: `std::placeholders`命名空间中定义,常用`_1`到`_9`。 - **数学表示**: 占位符对应函数参数映射,例如`bind(f, a, _1)`等价于函数$$g(x) = f(a, x)$$[^3]。 #### 示例3: 绑定成员函数(对象绑定) 成员函数需要绑定到具体对象指针,因为成员函数有隐含的`this`指针。类似引用[2]的示例。 ```cpp #include <iostream> #include <functional> class MyClass { public: void print(int a, int b) { std::cout << "a: " << a << ", b: " << b << std::endl; } }; int main() { MyClass obj; // 绑定成员函数:指定对象指针(&obj)和参数 auto boundFunc = std::bind(&MyClass::print, &obj, 10, std::placeholders::_1); boundFunc(20); // 输出: a: 10, b: 20 // 绑定成员函数并固定所有参数 auto fixedFunc = std::bind(&MyClass::print, &obj, 30, 40); fixedFunc(); // 输出: a: 30, b: 40 return 0; } ``` - **解释**: `std::bind(&MyClass::print, &obj, ...)`中,`&MyClass::print`是成员函数指针,`&obj`是对象指针。占位符处理动态参数。 - **注意事项**: 对象必须有效(避免野指针)。成员函数必须通过对象调用。 #### 示例4: 绑定函数对象或Lambda `std::bind`也可以绑定到函数对象(Functor)或Lambda表达式,实现更复杂逻辑。 ```cpp #include <iostream> #include <functional> // 定义函数对象 struct Adder { int base; Adder(int b) : base(b) {} int operator()(int x) const { return base + x; } }; int main() { // 绑定函数对象 Adder add5(5); auto boundFunctor = std::bind(&Adder::operator(), &add5, std::placeholders::_1); std::cout << boundFunctor(10) << std::endl; // 输出: 15 // 绑定Lambda表达式 auto lambda = [](int x, int y) { return x * y; }; auto boundLambda = std::bind(lambda, std::placeholders::_1, 2); std::cout << boundLambda(5) << std::endl; // 输出: 10 (5*2) return 0; } ``` - **解释**: 函数对象需要指定操作符函数(如`operator()`)。Lambda表达式可直接绑定。 - **推荐**: 在新C++代码中(C++11+),Lambda通常更简洁(示例参考引用[4])。 ### 3. 注意事项与常见问题 - **性能**: `std::bind`创建的对象可能比Lambda稍慢,但优化后可忽略。占位符会增加编译开销。 - **占位符顺序**: 占位符按`_1, _2`等顺序索引调用时的参数,不强制连续。 - **参数传递**: 参数按值传递(除非使用`std::ref`包裹)。 - **与Lambda比较**: Lambda更灵活(可直接捕获变量),但`bind`在固定成员函数时更简单。 - **错误避免**: 确保对象生命周期有效;模板参数推导注意(使用`auto`简化)。 数学上,`std::bind`实现了函数组合和部分应用的范畴论概念[^3]。 ### 4. 相关问题 基于您的查询,我生成了以下相关问题供进一步学习:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值