4
typedef boost::function<void (int,bool)> MyCallback;
void RegisterCallback(MyCallback callback);

class A {
public:
    void GoodCallback(int intArg,bool boolArg) {
        printf("calling GoodCallback (%d,%s)\n",intArg,boolArg?"true":"false");
    }

    void BadCallback(int intArg) {
        printf("calling BadCallback (%d)\n",intArg);
    }
};

int TestFunction() {
    A * myA=new A();
    RegisterCallback(boost::bind(&A::GoodCallback,myA,_1,_2));

    RegisterCallback(boost::bind(&A::BadCallback,myA,_1));

    return 0;
}

有什么方法可以使第二次调用 RegisterCallback 不编译?

对于上下文:
我最近更改了回调签名并添加了 bool 参数。我以为我已经更新了所有使用它的东西,但我错了。除了RegisterCallback每次更改签名时重命名之外,我还想有一种方法让编译器强制使用所有参数。

4

4 回答 4

2

文件说

任何额外的参数都会被默默地忽略

必须采用这种方式才能支持_N占位符。见证:

void foo (int a, const char* b) {
  std::cout << "called foo(" << a << "," << b << ")" << std::endl;
}

int main () {
  boost::bind(foo,_1, _2)(1, "abc", foo, main, 2.0);
  boost::bind(foo,_2, _5)(3.0, 2, foo, main, "def");
}

印刷

called foo(1,abc)
called foo(2,def)

可以忽略参数列表开头、结尾或中间的任何参数组合。

您需要一个不支持_N占位符之类的更简单的活页夹。Boost似乎没有。

于 2011-07-26T22:11:13.010 回答
1

问题不是boost::function;问题是函数对象boost::bind返回将把任何东西作为参数。Bind 或多或少是运行时定义的,而不是编译时定义的。因此,该boost::bind对象可以与任何boost::function.

[编辑] OK,显然boost::function也是问题。但这不是唯一的问题。

于 2011-07-26T20:53:07.027 回答
1

您可以随时使用std::function<...>

以下内容无法在 VS2010 SP1 上编译:

#include <functional>

void foo();
void bar(int);

int main()
{
    std::function<void ()> f= std::bind(foo);
    std::function<void ()> g= std::bind(bar); // does not match signature, does not compile.
    return 0;
}
于 2011-07-27T01:10:01.870 回答
0

我对这个答案有点晚了,但是由于问题是绑定,您可以稍后借助回调注册函数的模板版本和常规函数指针的另一个模板版本来执行此步骤:

template<typename C>
void RegisterCallback(void (C::* func)(int, bool), C* inst)
{
  MyCallback callback(boost::bind(func, inst, _1,_2));
}

void RegisterCallback(void (*func)(int, bool))
{
  MyCallback callback(func);
}

A * myA = new A();     
RegisterCallback(&A::GoodCallback, myA);      
RegisterCallback(&A::BadCallback, myA); // DOES NOT COMPILE

RegisterCallback(GoodCallback);
RegisterCallback(BadCallback); // DOES NOT COMPILE

这在 VS2010 中按预期工作,但缺点是不需要一个而是两个回调注册函数来正确处理成员和非成员函数。

作为另一种选择,您可以查看 boost function_types 库。它提供了一个 parameter_types 元函数,用于提取函数指针的参数类型并将它们作为 MPL 序列返回。然后使用一点模板魔法就可以验证回调函数的参数,例如:

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/equal.hpp>

using namespace boost;
using namespace boost::function_types;

template< typename Function >
void RegisterCallback(Function f)
{
   BOOST_MPL_ASSERT(( 
      mpl::equal< 
        parameter_types< Function >, 
        parameter_types< void(int,bool) >
      > 
   ));

   MyCallback callback(f);
}

template<typename Function, typename T>
void RegisterCallback(Function f, T* inst)
{
   BOOST_MPL_ASSERT(( 
     mpl::equal< 
       parameter_types< Function >, 
       parameter_types< void (T::*)(int,bool) >
     > 
   ));

   MyCallback callback(boost::bind(f, inst, _1, _2));  
}

这在 VS2010 中也可以按预期工作,但是您仍然需要两个函数声明,尽管如果您在结构中定义它们(并为 T 使用默认模板参数参数),应该可以将它们打包成一个;

于 2011-07-28T11:10:14.643 回答