Вопрос по member-function-pointers, c++ – Как лучше всего передавать методы в методы одного и того же класса

7

У меня есть этот класс C ++, что один большой сложный методcompute что я хотел бы передать с помощью «вычислительного ядра», метод того же класса. Я полагаю, что я бы сделал что-то вроде

class test {
int classVar_ = 42;

int compute_add(int a, int b)
{
   compute(int a, int b, this->add_())
}

int compute_mult(int a, int b)
{
   compute(int a, int b, this->mult_())
}


int compute_(int a, int b, "pass in add or multiply as f()")
{
   int c=0;
   // Some complex loops {
   c += f(a,b)
   // }
   return c;
}

int add_(int a, int b){a+b+classVar_;}
int multiply_(int a, int b){a*b+classVar_;}
...

}

но я не уверен, как мне пройтиadd или жеmultiply. An alternative to this approach would be to pass in an ENUM какой-то, чтобы указатьadd() или жеmultiply(), но я хотел избежатьswitch или жеif внутри петель.

Какова лучшая практика здесь?

@ Крис, я думаю, он запутался в синтаксисе? RedX
@RedX, на самом деле не проблема с Google, видя, как это довольно распространенная тема для исходного кода. chris
У тебя естьmember-function-pointers тег. Разве это не хорошее место для начала? chris
Если методы, которые вы хотите передать, такие же, как в вашем примере, то простые (статические) функции & amp; достаточно простых указателей на функции. Mat

Ваш Ответ

3   ответа
1

int compute(int a, int b, int (test::*f) (int, int) )
{
   int c=0;
   // Some complex loops {
   c += (this->*f)(a,b)
   // }
   return c;
}
5

передача указателя на функцию-член является приемлемой практикой.

Если вам нужно знать синтаксис, это:

int compute_(int a, int b, int (test::*f)(int,int))
{
   int c=0;
   // Some complex loops {
   c += (this->*f)(a,b)
   // }
   return c;
}

Представление функций-членов с использованием целых чисел и переключений вводит накладные расходы программиста, чтобы поддерживать актуальность при изменении списка доступных операций. Таким образом, вы не хотите этого, если в конкретном случае нет какой-либо важной причины.

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

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
    // body as before but `f(a,b)` instead of `(this->*f)(a,b)`
}

Этот более общий шаблон хорош, если кто-то хочет использовать его с каким-то оператором своего изобретения, который не является функцией-членомtest, Однако это труднее использовать в случае функции-члена, потому что кто-то должен захватитьthis, Есть несколько способов сделать это - лямбда C ++ 11,boost::bindили выписывая функтор от руки. Например:

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
    // body as before with `f(a,b)`
}

int compute_(int a, int b, int (test::*f)(int,int))
{
    return compute_(a, b, bind_this(f, this));
}

определяющийbind_this немного боли: это какstd::bind1st за исключением того, что мы хотели бы работать с 3-аргументным функтором, тогда какbind1st принимает только двоичный функторboost::bind, а такжеstd::bind в C ++ 11 более гибкие и будут обрабатывать дополнительные аргументы. Следующее будет делать для этого случая, но в целом не работает для связывания двухэлементных функций-членов:

struct bind_this {
    int (test::*f)(int,int);
    test *t;
    int operator(int a, int b) const {
        return (t->*f)(a,b);
    }
    bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) {}
};

В C ++ 11 вы можете просто использовать лямбду:

int compute_(int a, int b, int (test::*f)(int,int))
{
    return compute_(a, b, [=](int c, int d){ return (this->*f)(c,d) });
}
@Nico: попробуйте простоcompute_(1,2,add_).
@ Мат Ну, это то же самое, чтоthis->add_, дополнительный квалификатор только говорит компилятору, где искатьadd_. Nico Schlömer
@Nico: я бы назвал этоcompute_(1,2,&test::add_), но я готов поверить, что предложение Мата верно в рамках классаtest, очевидноthis->_add являетсяnot такой же как_add при формировании указателя на функцию-член, даже если при вызове этой функции-члена то же самое.
GCC более конкретен:ISO C++ forbids taking the address of a bound member function to form a pointer to member function. (Это для случая с&). я нашелstackoverflow.com/questions/2374847/… быть очень похожим вопросом. Позвольте мне проверить это. Nico Schlömer
Как бы вы позвонилиcompute_(int a, int b, int (test::*f)(int,int))? compute_(1,2,this->add_) доходностьcannot initialize a parameter of type 'int (test::*)(int, int)' with an rvalue of type '<bound member function type>'. compute_(1,2,&this->add_) доходностьcannot create a non-constant pointer to member function. Nico Schlömer
1

using pointer to member function using lambda functions

Пример использования указателя на функцию-член:

#include <iostream>

class D
{
public:
  D(int v ) : classVar_(v){}
  int add_(int a, int b){return (a+b+classVar_);}
  int multiply_(int a, int b){return (a*b+classVar_);}
private:
  int classVar_;
};

class test {
public:

int compute_(int a, int b, D &d, int (D::*f)(int a, int b))
{
   int c=0;
   // Some complex loops {
   c += (d.*f)(a,b);
   // }
   return c;
}

};

int main()
{
  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, d, &D::add_ ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, d, &D::multiply_ ) << std::endl;
}

Пример использования лямбды:

#include <iostream>
#include <functional>

class D
{
public:
  D(int v ) : classVar_(v){}
  int add_(int a, int b){return (a+b+classVar_);}
  int multiply_(int a, int b){return (a*b+classVar_);}
private:
  int classVar_;
};

class test {
public:

int compute_(int a, int b, std::function< int(int,int) > f)
{
   int c=0;
   // Some complex loops {
   c += f(a,b);
   // }
   return c;
}

};

int main()
{
  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.add_(a,b); } ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.multiply_(a,b); } ) << std::endl;
}
@Nico Да, вы можете объединить их. Я разделил их, потому что это делает пример более общим.
Можно ли объединить классыtest а такжеD? Nico Schlömer

Похожие вопросы