Здравствуйте, sokel, Вы писали:
S>ну а сигнатуру то всё равно нужно отдельным параметром передавать.
Можно выводить — если конечно то что выведется устроит. Но вывод не всегда возможен, например с шаблонами или перегрузкой — так что тут зависит от ситуации, думаю явная сигнатура предпочтительней.
S>Кстати, optional не съест noncopyable.
Здравствуйте, beyv, Вы писали:
B>Здравствуйте, AHOHUM, Вы писали:
B>Рекомендую FastDelegate, сам много лет использую для колбеков всех мастей. B>Желательно прочитать статью чтобы понять как оно работает.
Да, именно про эту статью я и писал выше, тут даже есть перевод её здесь
Здравствуйте, AHOHUM, Вы писали:
AHO>Здравствуйте, beyv, Вы писали:
B>>Здравствуйте, AHOHUM, Вы писали:
B>>Рекомендую FastDelegate, сам много лет использую для колбеков всех мастей. B>>Желательно прочитать статью чтобы понять как оно работает.
AHO>Да, именно про эту статью я и писал выше, тут даже есть перевод её здесь
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Это как раз std::function noncopyable не съест — особенности type-erasure (тут как раз нужен специальный тип a-la move_function).
std::function это да, там копирование не выпиливается потому что виртуализируется.
EP>Почему? Судя по документации — должен: 1, 2.
А с boost — ну у меня, видимо, boost старый — 1.55. Но похоже ещё и у bind с move присваиванием проблемы могут быть...
Свой storage для функтора позволяет понизить требование с move-assignable до move-constructible.
Или я что то не так делаю?
#include <iostream>
#include <memory>
#include <boost/optional.hpp>
// примерный optional, присваивание через perfect forwardtemplate<typename T>
struct opt_move_assign {
~opt_move_assign() {
if(constructed)
reinterpret_cast<T*>(&data)->~T();
}
template<typename U>
opt_move_assign& operator=(U&& x) {
if(constructed)
*(reinterpret_cast<T*>(&data)) = std::forward<U>(x);
else {
new (&data) T(std::forward<T>(x));
constructed = true;
}
return *this;
}
bool constructed = false;
typename std::aligned_storage<sizeof(T)>::type data;
};
// примерный optional, присваивание не используетсяtemplate<typename T>
struct opt_move_construct {
~opt_move_construct() {
if(constructed)
reinterpret_cast<T*>(&data)->~T();
}
template<typename U>
opt_move_construct& operator=(U&& x) {
if(constructed) {
constructed = false;
reinterpret_cast<T*>(&data)->~T();
}
new (&data) T(std::forward<T>(x));
constructed = true;
return *this;
}
bool constructed = false;
typename std::aligned_storage<sizeof(T)>::type data;
};
template<template<class> class Storage, class F>
void test(F&& f) {
using store_type = std::decay<F>::type;
Storage<store_type> x;
x = std::forward<F>(f);
}
struct foo {
void bar() {}
};
int main() {
// вот это ок, компилится
test<opt_move_assign>(std::make_unique<int>(111));
test<opt_move_construct>(std::make_unique<int>(111));
// вот это уже нет (boost 1.55)
// test<boost::optional>(std::make_unique<int>(111));
// а вот тут уже bind, вылезает copy tuple
// test<opt_move_assign>(std::bind(&foo::bar, std::make_unique<foo>()));
// хотя через move-construct всё ok
test<opt_move_construct>(std::bind(&foo::bar, std::make_unique<foo>()));
// ну как и в предыдушем варианте, тоже беда...
// test<boost::optional>(std::bind(&foo::bar, std::make_unique<foo>()));return 0;
}
Здравствуйте, sokel, Вы писали:
S>Но похоже ещё и у bind с move присваиванием проблемы могут быть... S>Свой storage для функтора позволяет понизить требование с move-assignable до move-constructible. S>Или я что то не так делаю?
А, ну собственно по стандарту никто и не требует от bind быть MoveAssignable:
The return type shall satisfy the requirements of MoveConstructible. If all of FD and TiD
satisfy the requirements of CopyConstructible, then the return type shall satisfy the requirements
of CopyConstructible. [ Note: This implies that all of FD and TiD are MoveConstructible. — end
note ]
Здравствуйте, Zenden, Вы писали:
Z>Разве оно умеет "Метод класс как С колбек" ?
Да, умеет (если вставить недостающие буквы в "Метод класс как С колбек" )
там есть примеры в FastDelegateDemo.cpp
примерно так
using namespace fastdelegate;
// Это классclass CClass {
public:
// Это метод классаint Function(int num, char *str);
};
int main(void){
// Обьявляете тип делегата (параметр1, параметр2, тип результата)typedef FastDelegate2<int, char *, int> FunctionDelegate;
// Создаете класс
CClass a();
// "deleg" - переменная-колбек, цепляем на неё метод класса
FunctionDelegate deleg = MakeDelegate(&a, &CClass::Function);
// вызываем метод класса как простую функциюint ret = deleg(5, "foo");
}
Здравствуйте, beyv, Вы писали:
B>Здравствуйте, Zenden, Вы писали:
Z>>Разве оно умеет "Метод класс как С колбек" ?
B>Да, умеет (если вставить недостающие буквы в "Метод класс как С колбек" )
B>там есть примеры в FastDelegateDemo.cpp
Неа, не умеет. Задачу автора (и мою) не решает.
У fastdelegate просто перегружен operator(), а нужен простой указатель на фукнцию.
Здравствуйте, Zenden, Вы писали:
Z>Неа, не умеет. Задачу автора (и мою) не решает. Z>У fastdelegate просто перегружен operator(), а нужен простой указатель на фукнцию.
Даа, умеет. Задача автора: "Метод класс как С колбек" а не "простой указатель на фукнцию"
Переменную "FunctionDelegate deleg" (из примера) можно использовать как угодно — брать адрес, передавать как параметр, запускать в космос...
Если "задача" у вас поизвращатся и пытатся изобрести велосипед, ну чтож...
Здравствуйте, beyv, Вы писали:
B>Здравствуйте, Zenden, Вы писали:
Z>>Неа, не умеет. Задачу автора (и мою) не решает. Z>>У fastdelegate просто перегружен operator(), а нужен простой указатель на фукнцию.
B>Даа, умеет. Задача автора: "Метод класс как С колбек" а не "простой указатель на фукнцию" B>Переменную "FunctionDelegate deleg" (из примера) можно использовать как угодно — брать адрес, передавать как параметр, запускать в космос... B>Если "задача" у вас поизвращатся и пытатся изобрести велосипед, ну чтож...
На этом, как вы говорите, "извращении" немало библиотек построено — например ATL, WTL.
Задача дана вполне конкретная, общего решения так и не предложено.
fastdelegate хорошая вещь, я ее использую в своих проектах, но в данном случае она приведена не к месту.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, beyv, Вы писали:
B>>Даа, умеет. Задача автора: "Метод класс как С колбек" а не "простой указатель на фукнцию"
EP>Прочитай изначальное сообщение, а не только его заголовок.
Прочитайте исходные код FastDelegate, прежде чем умничать.
Основная загвоздка у ТС получения доступа к полям класса в теле колбека или где там.
Пожалуйста, получите от делегата указатель "This", приведите его к классу и вот вам класс
#include"stdafx.h"#include"FastDelegate.h"using namespace fastdelegate;
// Это классclass CClass {
protected:
char *m_name;
public:
CClass(char *name) : m_name(name) {};
// Это метод классаint Function(int num, char *str) {
printf("In Function in %s. Num=%d, str = %s\n", m_name, num, str); return -1;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
typedef FastDelegate2<int, char *, int> FunctionDelegate;
// Создаете класс
CClass a("Base A");
// "deleg" - переменная-колбек
FunctionDelegate deleg;
// цепляем на неё метод класса и можем передать его куда угодно
deleg = MakeDelegate(&a, &CClass::Function);
// можем использовать как функцию
deleg(7, "tr");
// Чуть поизвращаясь, можно получить указатель на сам классconst detail::ClosurePtr<int, char *, int>& p = (const detail::ClosurePtr<int, char *, int>&)deleg.GetMemento();
CClass* ap = (CClass*)p.GetClosureThis();
// Получили класс со всеми потрохами
ap->Function(77, "ааааа");
return 0;
}
Здравствуйте, beyv, Вы писали:
B>>>Даа, умеет. Задача автора: "Метод класс как С колбек" а не "простой указатель на фукнцию" EP>>Прочитай изначальное сообщение, а не только его заголовок. B>Прочитайте исходные код FastDelegate,
И в чём там принципиальное отличие от std::function в рамках вопроса ТС?
B>прежде чем умничать.
О, вот уже и хамство пошло в ход — классный аргумент, главное универсальный
B>Основная загвоздка у ТС получения доступа к полям класса в теле колбека или где там. B>Пожалуйста, получите от делегата указатель "This", приведите его к классу и вот вам класс
И что это даст в случае ТС?
AHO>Имеется С библиотека с неизменяемым интерфейсом, одна из функций выглядит так:
AHO>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>[/q] EP>Эта библиотека принимает только указатель на функцию, и не позволяет прямым способом передать контекст — чем тут поможет этот FastDelegate?
Здравствуйте, beyv, Вы писали:
EP>>И в чём там принципиальное отличие от std::function в рамках вопроса ТС? B>FastDelegate инкапсулирует в себе и "this" и "метод класса"
Точно также как и std::function + std::bind, только проблему ТС это никак не решает
Здравствуйте, beyv, Вы писали:
EP>>Эта библиотека принимает только указатель на функцию, и не позволяет прямым способом передать контекст — чем тут поможет этот FastDelegate? B>В с(++) есть скобочки: B>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, beyv, Вы писали:
EP>>>И в чём там принципиальное отличие от std::function в рамках вопроса ТС? B>>FastDelegate инкапсулирует в себе и "this" и "метод класса"
EP>Точно также как и std::function + std::bind, только проблему ТС это никак не решает
Ну вы даете, я вам нарисовал как сделать делегата(колбек) на экземпляр любого класса и любой его метод(хоть с 6 параметрами),
как передать его в "void addCallback(void * internalState, Callback * callback);" вместо "callback"
как извлечь из переданого делегата экземпляр переданого класса и делать с ним что угодно
и это не решает проблему ТС ?
Боюсь даже спрашивать какая ещё тут проблема, кривые руки? непонимание чужого кода?
Здравствуйте, beyv, Вы писали:
EP>>>>И в чём там принципиальное отличие от std::function в рамках вопроса ТС? B>>>FastDelegate инкапсулирует в себе и "this" и "метод класса" EP>>Точно также как и std::function + std::bind, только проблему ТС это никак не решает B>Ну вы даете, я вам нарисовал как сделать делегата(колбек) на экземпляр любого класса и любой его метод(хоть с 6 параметрами), B>как передать его в "void addCallback(void * internalState, Callback * callback);" вместо "callback"
Этот callback будет использоваться внутри именно как указатель на функцию (то есть будет совершён вызов кода по этому адресу), вместо которого ты пытаешься передать указатель на экземпляр класса FastDelegate.
То есть получается что-то типа: LIVE DEMO