ссылка на функцию-член с помощью bind1st и mem_fun - PullRequest
9 голосов
/ 03 августа 2010

У меня есть класс C ++, где я пытаюсь использовать std :: bind1st для привязки функции-члена к параметру 'this'.Например:

class MyClass
{
public:
   void Foo()
   {
       using namespace std;

       // this works fine
       this->Bar();

       // this also works fine
       mem_fun( &MyClass::Bar )( this );

       // this does not
       bind1st( mem_fun( &MyClass::Bar ), this )();

       // this is not a possibility for this program
       boost::bind( &MyClass::Bar, this )();
   };

   void Bar()
   {
   };
};

Когда я добавляю эту последнюю строку 'bind1st', я получаю следующие ошибки компилятора:

1>stl/_function.h(189) : error C2039: 'second_argument_type' : is not a member of 'stlp_std::mem_fun_t<_Ret,_Tp>'
1>        with
1>        [
1>            _Ret=void,
1>            _Tp=MyClass
1>        ]
1>        .\MyClass.cpp(50) : see reference to class template instantiation 'stlp_std::binder1st<_Operation>' being compiled
1>        with
1>        [
1>            _Operation=stlp_std::mem_fun_t<void,MyClass>
1>        ]
1>stl/_function.h(189) : error C2146: syntax error : missing ',' before identifier 'second_argument_type'
1>stl/_function.h(189) : error C2065: 'second_argument_type' : undeclared identifier
1>stl/_function.h(190) : error C2955: 'stlp_std::unary_function' : use of class template requires template argument list
1>        stl/_function_base.h(40) : see declaration of 'stlp_std::unary_function'
1>stl/_function.h(191) : error C2039: 'second_argument_type' : is not a member of 'stlp_std::mem_fun_t<_Ret,_Tp>'
1>        with
1>        [
1>            _Ret=void,
1>            _Tp=MyClass
1>        ]
1>stl/_function.h(191) : error C2146: syntax error : missing ',' before identifier 'second_argument_type'
1>stl/_function.h(191) : error C2065: 'second_argument_type' : undeclared identifier
1>stl/_function.h(194) : error C2955: 'stlp_std::unary_function' : use of class template requires template argument list
1>        stl/_function_base.h(40) : see declaration of 'stlp_std::unary_function'
1>stl/_function.h(195) : error C2955: 'stlp_std::unary_function' : use of class template requires template argument list
1>        stl/_function_base.h(40) : see declaration of 'stlp_std::unary_function'
1>stl/_function.h(197) : error C2146: syntax error : missing ';' before identifier '_ArgParamType'
1>stl/_function.h(197) : error C3254: 'stlp_std::binder1st<_Operation>' : class contains explicit override 'param_type' but does not derive from an interface that contains the function declaration
1>        with
1>        [
1>            _Operation=stlp_std::mem_fun_t<void,MyClass>
1>        ]
1>stl/_function.h(197) : error C2838: 'param_type' : illegal qualified name in member declaration
1>stl/_function.h(197) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(197) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(198) : error C2146: syntax error : missing ';' before identifier '_ConstArgParamType'
1>stl/_function.h(198) : error C3254: 'stlp_std::binder1st<_Operation>' : class contains explicit override 'const_param_type' but does not derive from an interface that contains the function declaration
1>        with
1>        [
1>            _Operation=stlp_std::mem_fun_t<void,MyClass>
1>        ]
1>stl/_function.h(198) : error C2838: 'const_param_type' : illegal qualified name in member declaration
1>stl/_function.h(198) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(198) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(199) : error C2039: 'first_argument_type' : is not a member of 'stlp_std::mem_fun_t<_Ret,_Tp>'
1>        with
1>        [
1>            _Ret=void,
1>            _Tp=MyClass
1>        ]
1>stl/_function.h(199) : error C2146: syntax error : missing ',' before identifier 'first_argument_type'
1>stl/_function.h(199) : error C2065: 'first_argument_type' : undeclared identifier
1>stl/_function.h(199) : error C2955: 'stlp_std::__call_traits' : use of class template requires template argument list
1>        stl/type_traits.h(452) : see declaration of 'stlp_std::__call_traits'
1>stl/_function.h(203) : error C2039: 'first_argument_type' : is not a member of 'stlp_std::mem_fun_t<_Ret,_Tp>'
1>        with
1>        [
1>            _Ret=void,
1>            _Tp=MyClass
1>        ]
1>stl/_function.h(203) : error C2146: syntax error : missing ';' before identifier '_M_value'
1>stl/_function.h(203) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(203) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>stl/_function.h(208) : error C2061: syntax error : identifier '_ConstArgParamType'
1>stl/_function.h(211) : error C2061: syntax error : identifier '_ArgParamType'
1>stl/_function.h(212) : error C2535: '_Result stlp_std::binder1st<_Operation>::operator ()(void) const' : member function already defined or declared
1>        with
1>        [
1>            _Operation=stlp_std::mem_fun_t<void,MyClass>
1>        ]
1>        stl/_function.h(208) : see declaration of 'stlp_std::binder1st<_Operation>::operator ()'
1>        with
1>        [
1>            _Operation=stlp_std::mem_fun_t<void,MyClass>
1>        ]

Я использую STLPort v5.2.1 для реализации стандартной библиотеки.

Обычно я переключаюсь на boost :: bind и использую это.К сожалению, это невозможно для этого приложения.

Что я могу сделать, чтобы получить нужную функциональность?

Спасибо, PaulH


Редактировать: Чтобы быть более понятным, я ищу способ приспособить унарную функцию к тому, что вы называете функцией, которая не принимает параметров.Я хочу связать this с MyClass::Bar.

class SomeOtherClass
{
public:
    template< typename Fcn >
    void ExecuteFcn( Fcn fcn )
    {
        fcn();
    };
};

some_other_class.ExecuteFcn( bind1st( mem_fun( &MyClass::Bar ), this );

Ответы [ 4 ]

5 голосов
/ 03 августа 2010

Чего вы пытаетесь достичь с помощью bind1st?

Функция bind1st берет двоичную функцию и адаптирует ее к унарной функции, делая первый аргумент неявным (это может быть не лучшим описанием, извините).Возвращаемое значение mem_fun является унарной функцией.

Функция mem_fun возвращает адаптер для функции-члена.Адаптированная функция не принимает никаких аргументов, хотя возвращаемый адаптер принимает один аргумент - указатель на объект MyClass, который будет использоваться.

Так что, в основном, ваш вызов mem_fun возвращает адаптер, который принимает одинаргумент, но bind1st ожидает адаптер, который принимает два аргумента.Существует mem_fun1, который возвращает адаптер, который принимает два аргумента, первый - указатель объекта, а второй - аргумент функции, но это не то, что вам нужно.

На самом деле,Я не совсем понимаю, что вы пытаетесь сделать;почему простая mem_fun версия не подходит?Если вам нужно, чтобы указатель объекта был «присоединен» к адаптеру, я не думаю, что вы можете сделать это с текущей стандартной библиотекой, если только вы не используете bind.

Конечно, вы можете создать класс-оболочкукоторый содержит указатель на объект, а затем просто определите operator () для вызова адаптера с этим объектом.

// Quick and dirty example of this.
// You could extend this with a second template parameter for return type, if
// needed. Just be sure to specialize for void if you do that.
template<typename Object>
struct bound_mem_fun_t { 
    bound_mem_fun_t(mem_fun_t<void, Object> f, Object* o) : fun(f), obj(o) { } 
    void operator()() { fun(obj); } 
    mem_fun_t<void, Object> fun; 
    Object* obj; 
};

MyClass a;
bound_mem_fun_t<MyClass> func(mem_fun(&MyClass::Bar), &a);
func();
4 голосов
/ 03 августа 2010

bind1st требует бинарную функцию и возвращает унарный функтор. Здесь вы передаете унарную функцию.

Цель «связывания» состоит в том, чтобы использовать бинарную функцию / функтор (как нестатический метод с одним параметром), как унарный, путем установки одного из его параметров в заданное значение.

Это будет работать (обратите внимание на новый прототип Bar):

class MyClass
{
public:
   void Foo()
   {
       using namespace std;

       // this works fine
       bind1st( mem_fun( &MyClass::Bar ), this )(42);
   };

   void Bar(int i)
   {
   };
};
1 голос
/ 04 сентября 2013

Я хотел добавить к этому еще одно возможное решение, использующее лямбда-функции из C ++ 11.

Вот краткий пример:

class MyClass
{
    std::string mName;

public:
   MyClass(const char* name) : mName(name) {};

   void Foo()
   {
       std::cout << "My name is " << mName << std::endl;
   };
};

void CallMyFn(std::function<void()> fn)
{
    fn();
}

int main()
{
    MyClass myInstance("Ishmael");

    CallMyFn( [&]() { myInstance.Foo(); } );

    return 0;
}

Вывод:«Меня зовут Измаил.»

0 голосов
/ 03 августа 2010

Я считаю, что это не работает, потому что bind1st() требует двоичный объект функции и возвращает унарный объект функции.Поскольку Bar() не принимает аргументов, mem_fun() предоставляет вам унарный объект функции.bind1st() не знает, что с этим делать.

Как вы на самом деле намереваетесь использовать объект функции, созданный mem_fun()?

...