使用boost-bind,生成的boost-function可能会收到比绑定对象所期望的更多的参数。从概念上讲:
int func() { return 42; }
boost::function<int (int,int,int)> boundFunc = boost::bind(&func);
int answer = boundFunc(1,2,3);
在这种情况下,func()
在堆栈上接收1,2和3,即使它的签名表明它不带参数。
这与boost::bind
对partial application的更典型用法不同,其中某些对象的值是固定的,产生的boost::function
占用较少的参数,但提供正确的数量参数在调用绑定对象时。
以下代码适用于MSVC ++ 2010 SP1。这是一种简化形式的帖子;原始代码也适用于Linux上的g ++ 4.4。
以下是根据C ++标准明确定义的吗?
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
using namespace std;
void func1(int x) { std::cout << "func1(" << x << ")\n"; } // end func1()
void func0() { std::cout << "func0()\n"; } // end func0()
int main(int argc,char* argv[])
{
typedef boost::function<void (int)> OneArgFunc;
OneArgFunc oneArg = boost::bind(&func1,_1);
// here we bind a function that accepts no arguments
OneArgFunc zeroArg = boost::bind(&func0);
oneArg(42);
// here we invoke a function that takes no arguments
// with an argument.
zeroArg(42);
return 0;
} // end main()
我理解为什么zeroArg(42)
有效:未使用的参数由调用例程放在堆栈上,而不被被调用的例程访问。当被调用的例程返回时,调用例程清理堆栈。由于它将参数放在堆栈上,因此它知道如何删除它们。
转移到另一个架构或c++编译器会破坏这个吗?更积极的优化会打破这个吗?
我正在寻找更强有力的声明,无论是来自Boost文档还是来自Standards文档。我无法在两者中找到明确的立场。
使用调试器并查看程序集和堆栈,很明显第一个示例中的func
没有收到值1,2和3:您在这方面是正确的。第二个例子中的func0
也是如此。至少对于我正在研究的实现,MSVC ++ 2010SP1和g ++ 4.4 / Linux都是如此。
查看引用的Boost文档,并不像我想的那样清楚传递额外参数是安全的:
bind(f, _2, _1)(x, y); // f(y, x)
bind(g, _1, 9, _1)(x); // g(x, 9, x)
bind(g, _3, _3, _3)(x, y, z); // g(z, z, z)
bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)
请注意,在最后一个示例中,
bind(g, _1, _1, _1)
生成的函数对象不包含对第一个参数之外的任何参数的引用,但它仍可以与多个参数一起使用。 任何额外的参数都会被默默忽略,就像在第三个例子中忽略第一个和第二个参数一样。 [强调我的。]
关于额外参数被忽略的陈述并不像我想说服我在一般情况下这是正确的那样明确无误。查看TR1,从第3.6.3节可以清楚地看出,从bind
返回的可调用对象可以使用与目标对象不同的参数来调用期待。这是最好的保证吗?
答案 0 :(得分:15)
是的,这是安全且可移植的 - 如the documentation中明确提到的,boost::bind
返回的bind-expression默默地忽略了额外的参数。
即,在您的第一个示例中,func
不接收值1
,2
和3
- {{1}接收值boundFunc
,1
和2
并将它们转发到包含的bind-expression,它会安全地接收并忽略它们,然后调用3
。同样,在第二个示例中,func()
接收值zeroArg
并将其转发到包含的bind-expression,后者接收并忽略该值,然后调用42
。