LINUX.ORG.RU

Обернуть member function в std::function

 


0

2

Всем привет. Пусть есть примерно такое объявление:

typedef void (A::*Callback)(int);

Как сделать такое же объявление Callback, используя std::function?

typedef std::function<void (A::*)(int)> Callback;

При использовании такого объявления при передаче метода в функцию, скажем:

void a(Callback c) {...}
у меня не строится код с ошибкой «'c' has incomplete type». Как объявить правильно?

ЗЫ mem_fn() не предлагать, мне нужен определённый std::function вместо auto.

Перемещено JB из talks

★★★★★

Если у тебя заранее известен обьект, на котором будет вызываться функция, то захвати его лямбдой:

// this - в данном случае захватываемый обьект
auto callback = [this] (int arg) { this->method(arg); };

Если же ты хочешь использовать этот метод на заранее неизвестном объекте (прямо как указатель на метод), то никуда не денешься, нежели как явно передавать объект на котором будет вызван метод твоей std::function. Т.е. смысла использовать std::function в данном случае почти нет.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 3)

А зачем тебе оно? bind не хватит в данном случае?

UVV ★★★★★
()
std::function<void(int)> callback = std::bind(&A::Callback, &obj, std::placeholders::_1);

Это не то, что тебе надо?

wolph ★★
()
Ответ на: комментарий от UVV

Берёшь std::bind

и кладёшь эту бяку обратно. Как можно пользоваться убожеством, которое игнорирует передачу лишних параметров, помимо прочих прелестей?

quoob
()
Ответ на: комментарий от kachsheev

Нет, это генеральное представление любой функции, но оно по-моему не работает просто для методов классов, нужен еще и объект. Да, присвоить в него связку объект-метод проще всего через std::bind, и я не знаю, есть ли другой способ.

staseg ★★★★★
()
Ответ на: комментарий от quoob

Раскомментируй и обосрись

игнорирует передачу лишних параметров

class X{
public:
    void foo(int a){
        printf("%d\n", a);
    }
};

int main(){
    X x;
    std::function<void(int)> f = std::bind(&X::foo, x, std::placeholders::_1/*, 1*/);
    f(42);
    return 0;
}

error: no viable conversion from '__bind<void (X::*)(int), X &, std::__1::placeholders::__ph<1>
&, int>' to 'std::function<void (int)>'
std::function<void(int)> f = std::bind(&X::foo, x, std::placeholders::_1, 1);

staseg ★★★★★
()
Последнее исправление: staseg (всего исправлений: 2)
Ответ на: комментарий от UVV

this is safe and portable

Кто-то сказал, что оно unsafe или не portable?

Нет, было сказано другое. Что это лютое говно, которое появилось в стандарте по неудачному стечению исторических обстоятельств (на тот момент лямбды были сыроваты и было толком не ясно, в каком виде они будут).

соснули?

Ну кто-то точно соснул, факт :)

quoob
()
Ответ на: комментарий от staseg

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

quoob
()

Как объявить правильно?

Всё очень и очень просто:

std::function<void(A&, int)> callback = static_cast<void (A::*)(int)>(&A::method);
A a;
callback(a, 42);

Короче, такая же шняга как std::mem_fn. Сразу предупреждаю, моего плюсы-фу крайне недостаточно чтобы объяснить почему это работает.

Явное преобразование типов нужно чтобы был выбран правильный перегруженный метод. Может быть, можно как-то более умно поступить, но — ХЗ.

И да, аргументы передаваемые в метод по ссылке, должны идти обёрнутые в std::ref.

Я очень сильно не рекомендую пользоваться <functional>. Есть риск нарваться на массу неявных преобразований т.е. конструкторов копирования.

Macil ★★★★★
()
Последнее исправление: Macil (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.