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之外,我还希望有一种方法使编译器强制使用所有参数。

最佳答案

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

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使用默认的模板参数参数)也可以将它们打包在一起。

09-07 07:32