【问题标题】:How can I make boost::function not be so lenient?我怎样才能让 boost::function 不那么宽松?
【发布时间】:2011-07-26 20:49:40
【问题描述】:
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 之外,我还希望有一种方法可以让编译器强制使用所有参数。

【问题讨论】:

    标签: c++ boost boost-function


    【解决方案1】:

    文档说

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

    必须采用这种方式才能支持_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 好像没有。

    【讨论】:

      【解决方案2】:

      问题不在于boost::function;问题是函数对象boost::bind 返回将把 anything 作为参数。绑定或多或少是运行时定义的,而不是编译时定义的。因此,boost::bind 对象可以与任何boost::function 一起使用。

      [edit] 好的,显然boost::function 也是 一个问题。但这不是唯一的问题。

      【讨论】:

      • boost::function 也将接受几乎所有内容,并且在实际调用该函数之前不会抱怨。
      • @Dennis:我猜如果没有概念,就无法验证特定对象是否可以使用特定模板参数签名进行调用。
      • @Nicol 你可以尝试用declvaldecltype 来断言。
      【解决方案3】:

      您始终可以使用 std::function&lt;...&gt;

      以下内容无法在 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;
      }
      

      【讨论】:

      • 这个想法+1,也许有一天我的公司会从VS2005升级,我就可以使用它了。
      【解决方案4】:

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

      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 使用默认模板参数参数);

      【讨论】:

      • 需要三个注册函数void RegisterCallback(void (C::* func)(int, bool) const, const C* inst)
      • 是的,你是对的,这是使用函数重载注册回调的缺点——你需要为每个 const/non-const member/non-member volatile/non 提供重载-volatile 等。处理一般情况的签名组合和重载的数量随着参数计数呈指数增长。出于这个原因,我更倾向于使用 function_types 库来验证函数指针,因为这正是库试图解决的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-21
      • 2017-09-18
      • 2019-05-30
      • 2017-12-09
      • 2015-05-12
      • 1970-01-01
      相关资源
      最近更新 更多