25

使用,生成的可能会收到比绑定对象预期更多的参数。从概念上讲:

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::bindfor partial application用法不同,后者的某些对象的值是固定的,产生的 aboost::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)有效:调用例程将未使用的参数放在堆栈上,而被调用例程根本无法访问。当被调用例程返回时,调用例程清理堆栈。由于它将参数放在堆栈上,它知道如何删除它们。

迁移到另一个架构或编译器会破坏这一点吗?更积极的优化会打破这一点吗?


我正在寻找更强有力的声明,无论是来自 Boost 文档还是来自标准文档。我也找不到一个明确的立场。

使用调试器并查看程序集和堆栈,很明显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

4

1 回答 1

15

是的,这是安全且可移植的——正如文档中明确提到的,由boost::bind静默返回的绑定表达式会忽略额外的参数。

即,在您的第一个示例中,func接收值,和–接收值,并将它们转发到包含的绑定表达式,该绑定表达式安全地接收并忽略它们,然后调用. 同样,在您的第二个示例中,接收值并将其转发到包含的绑定表达式,该表达式接收并忽略该值,然后调用.123boundFunc123func()zeroArg42func0()

于 2011-09-12T21:43:13.670 回答