Как я могу сделать boost :: function не такой снисходительной? - PullRequest
4 голосов
/ 27 июля 2011
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 ]

2 голосов
/ 27 июля 2011

Документация гласит:

Любые дополнительные аргументы игнорируются

Это должно быть так, чтобы поддерживать _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 такого нет.

1 голос
/ 27 июля 2011

Вместо этого вы всегда можете использовать 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;
}
1 голос
/ 27 июля 2011

Проблема не в boost::function; проблема в том, что объект функции boost::bind возвращает в качестве параметров что угодно . Bind, более или менее, определяется во время выполнения, а не во время компиляции. Следовательно, объект boost::bind можно использовать с любым boost::function.

[править] ОК, очевидно, boost::function это также проблема. Но это не единственная проблема.

0 голосов
/ 28 июля 2011

Я немного опоздал с этим ответом, но поскольку проблема заключается в привязке, вы можете сделать этот шаг позже с помощью шаблонной версии для вашей функции регистрации обратного вызова и другой для обычных указателей функций:

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, но имеет недостаток в необходимости не одной, а двух функций регистрации обратного вызова, чтобы правильно работать с функциями-членами и не-членами.

В качестве другого варианта вы можете взглянуть наувеличить библиотеку 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);

...