Использование std:: function/mem_fn в С++ 11 с функциями-членами

100
11

Короче говоря, существует ли простой/определенный способ обтекания объектов функции /lambdas и функций-членов?


Если я правильно понимаю, если я использую std:: mem_fn, мне нужно передать объект правильного типа вызову функции, т.е.


Object o;
ftncall std::mem_fun(&Object::function);
ftncall(o);

В идеале, есть какой-то способ "прикрепить" o к этому объекту функции, возможно, как std::weak_ptr, поэтому мы знаем, что o удалено. Например, если есть способ сделать что-то неопределенно:


Object o;
ftncall std::mem_fn(&Object::function, o); // Or maybe std::mem_fn<Object>
ftncall();

Теперь, очевидно, этого не существует (насколько мне известно). Есть ли способ обернуть std:: mem_fn таким образом, чтобы я не терял общности (и красивости) std:: mem_fn, но могу "присоединить" o, и по-прежнему хорошо играть с другим типом функции, как std:: function? В идеале, я все еще мог бы использовать operator() в том, как я это делаю с помощью std:: function.


В настоящее время лучшим решением, о котором я могу думать, является класс, который выглядит следующим образом:


template<class T>
class MemFunWrapper {
public:
MemFunWrapper(T* t, std::mem_fun funct) : m_t(t), m_function(funct) {}

std::mem_fun operator*() { return m_function; }
T* get() { return m_t; }
private:
T* m_t;
std::mem_fun m_function;
}


Тогда вы можете использовать его таким образом:


(*MemFunWrapper)(MemFunWrapper->get(), args...);

Но это кажется мне довольно громоздким. Кроме того, мне пришлось бы создать эквивалентный класс для std:: function для того, чтобы его можно было использовать аналогичным образом, и это кажется глупым, поскольку я уже могу просто использовать std:: function. В идеале я также смогу использовать конечный продукт, не зная, вызываю ли я функцию-член или регулярную функцию. Я знаю, что я много прошу - любое направление было бы полезно. Большое спасибо!

спросил(а) 2013-09-03T07:41:00+04:00 7 лет, 1 месяц назад
1
Решение
134

То, что вы ищете, это std:: bind вместо std:: mem_fn:


#include <iostream>
#include <functional>

struct Object
{
void member()
{
std::cout << "yay!" << std::endl;
}
};

int main()
{
Object o;
auto fn = std::bind(&Object::member, o);
fn();
}

FWIW: существует предложение для добавления перегрузки в std:: mem_fn, принимающего объект для включения в С++ 14.

ответил(а) 2013-09-03T07:45:00+04:00 7 лет, 1 месяц назад
120

В С++ 11, как правило, это проще всего сделать с lambdas:


std::shared_ptr<Object> o;
auto ftncall = [o](){ if (o) o->function(); }
ftncall();

Если вам нужно стирать стили, просто введите его в std::function<void()>.

Lambdas в С++ 11 может выполнять ту же работу, что и bind, не полагаясь на функции библиотеки, чтобы сделать это, и я лично считаю их более читаемыми.


Есть ситуации, когда bind может выполнять лучшую работу в С++ 11, но в этот момент они являются угловыми (в С++ 1y больше углов также будут обрезаны).

ответил(а) 2013-09-03T17:01:00+04:00 7 лет, 1 месяц назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема