Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> возвратить из функции void? 
V
    Опции темы
bsa
Дата 28.10.2009, 17:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



tilin, правильно ли я тебя понял, тебе нужно создавать "задачу", которая в большинстве случаев выглядит как вызов: result = object->method(data)?
Если result всегда одного типа, то рекомендую обратить внимание на boost::bind (для создания "задач") и boost::function (для хранения "задач" в контейнере). Если разных типов, то еще и на boost::any.

например, у тебя есть метод int A::method(double x). Ты хочешь его поставить в очередь задач a->method(1.0), тогда boost::bind(&A::method, a, 1.0) создаст тебе объект, который можно вызывать так: o(). Чтобы этот объект чему-нибудь присвоить (пока нет auto из c++0x) можно использовать или шаблоны или boost::function: boost::function<int()> f = boost::bind(&A::method, a, 1.0). Теперь появился функциональный объект f, который можно вызвать так: f().

А вот это уже можно хранить в контейнере (для случая с any):
Код
struct Task {
   template<class Handler>
   Task(Handler handler) : handler_(handler), complete_(false) {}
   const boost::any& result() const { return result_; }
   bool complete() const { return complete_; }
   void operator()() {
       result_ = handler_();
       complete_ = true;
   }
private:
   boost::any result_;
   boost::function<boost::any()> handler_;
   bool complete_;
};


Это сообщение отредактировал(а) bsa - 28.10.2009, 17:43
PM   Вверх
tilin
Дата 28.10.2009, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(bsa @  28.10.2009,  17:37 Найти цитируемый пост)
tilin, правильно ли я тебя понял, тебе нужно создавать "задачу", которая в большинстве случаев выглядит как вызов: result = object->method(data)?
Если result всегда одного типа, то рекомендую обратить внимание на boost::bind (для создания "задач") и boost::function (для хранения "задач" в контейнере). Если разных типов, то еще и на boost::any.


Да надо создавать что-то типа задачи, которая хранит объект, метод, параметры вызова и возвращаемое значение. Однако результ может быть совершенно разного типа.
В сторону boost-а я уже начал смотреть, но пока с целью ознакомления только лишь.
Выложу свое решение, поправьте, если что не то сделал. Списки типов из библиотеки Loki. В Loki NullType.h заменено:

Код

typedef void NullType;
    //class NullType {};



Основная реализация такая:

Код

#include "loki/Typelist.h"

using namespace Loki;

class ICallObject
{
public:
    virtual void Call() = 0;
    virtual void SetReceiver(void* pObj) = 0;
    virtual ICallObject* Clone() = 0;
    virtual void* GetResult() = 0;
};

template <typename T, typename D, typename R, class C, int n>
class CallObject : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
    }

    ICallObject* Clone()
    {
        return new CallObject<>(*this);
    }

    void* GetResult()
    {
    
    }
};

template <typename T, typename D, typename R, class C>
class CallObject<T,D,R,C,0> : public ICallObject
{
public:
    T* pObject;
    D pFunc;
    
    R result;

    CallObject(T* _pObject, D _pFunc)
        :    pObject(_pObject), pFunc(_pFunc)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)();
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,0>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, class C>
class CallObject<T,D,void,C,0> : public ICallObject
{
public:
    T* pObject;
    D pFunc;
    
    CallObject(T* _pObject, D _pFunc)
        :    pObject(_pObject), pFunc(_pFunc)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)();
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,0>(*this);
    }

    void* GetResult()
    {
        return 0;
    }
};

template <typename T, typename D, typename R, typename C>
class CallObject<T,D,R,C,1> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;

    R result;
    Tp1 p1;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)(p1);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,1>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, typename C>
class CallObject<T,D,void,C,1> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    
    Tp1 p1;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)(p1);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,1>(*this);
    }

    void* GetResult()
    {
        return 0;    
    }
};


template <typename T, typename D, typename R, typename C>
class CallObject<T,D,R,C,2> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    typedef typename TL::TypeAt<C, 1>::Result Tp2;

    R result;
    Tp1 p1;
    Tp2 p2;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1, Tp2 _p2)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1), p2(_p2)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        result = (pObject->*pFunc)(p1, p2);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,R,C,2>(*this);
    }

    void* GetResult()
    {
        return &result;
    }
};

template <typename T, typename D, typename C>
class CallObject<T,D,void,C,2> : public ICallObject
{
public:
    T* pObject;
    D pFunc;

    typedef typename TL::TypeAt<C, 0>::Result Tp1;
    typedef typename TL::TypeAt<C, 1>::Result Tp2;

    Tp1 p1;
    Tp2 p2;

    CallObject(T* _pObject, D _pFunc, Tp1 _p1, Tp2 _p2)
        :    pObject(_pObject), pFunc(_pFunc), p1(_p1), p2(_p2)
    {
        
    }

    void SetReceiver(void* pObj)
    {
        pObject = static_cast<T*>(pObj);
    }

    void Call()
    {
        (pObject->*pFunc)(p1, p2);
    }

    ICallObject* Clone()
    {
        return new CallObject<T,D,void,C,2>(*this);
    }

    void* GetResult()
    {
        return 0;
    }
};

#define CallObj(A,O,F,...) CallObject<A,\
    A::T##F##,\
    A::T##F##ReturnType,\
    A::T##F##Types,\
    TL::Length<A::T##F##Types>::value>\
    co(O, &A::##F, __VA_ARGS__);


#define SETTYPES(Class, FName, Return,...)\
    typedef Return (##Class##::*T##FName##)(__VA_ARGS__);\
    typedef TL::MakeTypelist<__VA_ARGS__>::Result T##FName##Types;\
    typedef Return T##FName##ReturnType; 


Макросы только для удобства записи.

Пример использования. Func6 для примера без использования макроса  SETTYPES:

Код

#include "CallObject.h"
#include <iostream>

using namespace std;

class A
{
public:

    SETTYPES(A,Func1, void, void)
    void Func1(void)
    {
    }

    SETTYPES(A,Func2, int, void )
    int Func2(void)
    {
        return 100;
    }

    SETTYPES(A,Func3, int, int)
    int Func3(int d)
    {
        return d;
    }

    SETTYPES(A,Func4, void, int)
    void Func4(int d)
    {
        
    }

    SETTYPES(A,Func5, int, int, float)
    int Func5(int d, float f)
    {
        return d+f;
    }

    typedef void (A::*TFunc6)(int, float);
    typedef TL::MakeTypelist<int, float>::Result TFunc6Types;
    typedef void TFunc6ReturnType;
    void Func6(int d, float f)
    {
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    CallObj(A, &a, Func5, 12,130);

    co.Call();
    int res = (*static_cast<int*>(co.GetResult()));
    cout << res << endl;

    return 0;
}

PM MAIL   Вверх
bsa
Дата 29.10.2009, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



tilin, я тебе дал готовое решение, которое в разы проще и надежней твоего - используй его!

Забыл написать, как добавлять задачи. Допустим, есть менеджер задач, у которого есть метод добавления, объявленный так:
Код
template<class Handler>
void TaskManager::add(Handler handler);
То чтобы поставить на выполнение вызов:
Код
MyClass *object;
...
object->method(1.0, 2.0, "asdf");
 нужно написать:
Код
tm->add( boost::bind(&MyClass::method, object, 1.0, 2.0, "asdf") );


Кстати, начиная с версии 1.35 в boost уже есть менеджер задач! Вот только находится он в неочевидном месте и еще менее очевидно называется. Это boost::asio::io_service. Чтобы с ним работать нужно знать всего два метода: io_service::post() (постановка задачи на асинхронное исполнение), и io_service::run() (выполнение всех задач, пока они есть в очереди; может быть вызван одновременно в нескольких потоках, что приведет к параллельному исполнению задач).
PM   Вверх
Lazin
Дата 29.10.2009, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(bsa @  29.10.2009,  16:11 Найти цитируемый пост)
tilin, я тебе дал готовое решение, которое в разы проще и надежней твоего - используй его!
 smile 
а еще - функциональней, благодаря полиморфному поведению boost::function, в качестве задач можно использовать не толко ф-ии, но и методы и функторы, твой пример можно переписать вот так:

Код

...
#include <iostream>
using namespace std;
class A
{
public:
    void Func1(void)
    {
    }
    int Func2(void)
    {
        return 100;
    }
    int Func3(int d)
    {
        return d;
    }
    void Func4(int d)
    {  
    }
    int Func5(int d, float f)
    {
        return d+f;
    }
    void Func6(int d, float f)
    {
    }
};

class TaskManager
{
public:
    template<class H>
    void Add(H handler)
    {
         Task<H> task(handler);
         // сделать что-то с task, например:
         task();
         std::cout << task.result() << std::endl;
    }
    ...
};

int main(int argc, char* argv[])
{
    A a;
    boost::shared_ptr<A> p;
    p.reset(new A());
    TaskManager manager;
    manager.add( boost::bind<int>(&A::Func5, &a, 12, 130) );
    manager.add( boost::bind(&A::Func4, p, 42) );
    return 0;
}



Добавлено через 4 минуты и 51 секунду
Цитата(bsa @  28.10.2009,  17:37 Найти цитируемый пост)
struct Task {
   template<class Handler>
   Task(Handler handler) : handler_(handler), complete_(false) {}
   const boost::any& result() const { return result_; }
   bool complete() const { return complete_; }
   void operator()() {
       result_ = handler_();
       complete_ = true;
   }
private:
   boost::any result_;
   boost::function<boost::any()> handler_;
   bool complete_;
};

кстати, если нет желания использовать boost::asio::io_service, то можно просто сделать не шаблонный класс - наследник Task, у котрого был-бы определен виртуальный метод result, complete и operator() и работать с объектами Task - полиморфно

Код

class ITask
{
   virtual void operator () () = 0;
   ...
};

template<class Handler>
class Task : public ITask
{
...
};


Это сообщение отредактировал(а) Lazin - 29.10.2009, 16:47
PM MAIL Skype GTalk   Вверх
tilin
Дата 29.10.2009, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Все понял.
Честно, я понятия не имел, что если сделать вот так
Код

template <typename R, typename T, typename Arg>
void bind(R (T::*fn)(Arg), const T& t) 

а потом вот так
Код

bind(&A::Func, a);


То в bind будут автоматически определены типы. Я в шоке. Век живи - век учись )
PM MAIL   Вверх
bsa
Дата 29.10.2009, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(tilin @ 29.10.2009,  17:26)
Честно, я понятия не имел, что если сделать вот так
Код

template <typename R, typename T, typename Arg>
void bind(R (T::*fn)(Arg), const T& t) 

а потом вот так
Код

bind(&A::Func, a);

Решил свой аналог boost::bind сделать?  smile 
PM   Вверх
tilin
Дата 30.10.2009, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(bsa @  29.10.2009,  18:58 Найти цитируемый пост)
Решил свой аналог boost::bind сделать?  smile 

Просто очень хочется разобраться как делаются такие вещи  smile .
Вот что получяется. Я в правильном направлении?
Код

#include <iostream>


// ================================
class Base
{
public:
  virtual void Call() = 0;
  virtual void* GetResult() = 0;
};

template <typename R, typename T, typename Arg1, typename Arg2>
class CallObject : public Base
{
  typedef R (T::*TFunc)(Arg1, Arg2);
  TFunc func;
  T* object;
  R result;
  Arg1 ar1;
  Arg2 ar2;

public:
  CallObject(TFunc _func, T* _object, Arg1 _ar1, Arg2 _ar2) 
      : func(_func), object(_object) , ar1(_ar1), ar2(_ar2) 
  { }

  void Call()
  {
      result = (object->*func)(ar1,ar2);
  }
  void* GetResult()
  {
        return &result;
  }
};

template <typename R, typename T, typename Arg1, typename Arg2>
inline Base* CreateCallObject(
  R (T::*func)(Arg1, Arg2), 
  T* object, 
  Arg1 ar1,
  Arg2 ar2) 
{
  return new CallObject<R, T, Arg1, Arg2>(func, object, ar1,ar2);
}

// ================================


class A
{
public:
    float Func(int d, float f)
    {
        return d+f;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    Base* b = CreateCallObject(&A::Func, &a, 12, (float)24);
    b->Call();
    float res = *(static_cast<float*>(b->GetResult()));

    
    return 0;
}


PM MAIL   Вверх
mes
Дата 30.10.2009, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(tilin @  30.10.2009,  12:12 Найти цитируемый пост)
Вот что получяется. Я в правильном направлении?

весь код не смотрел, но судя по этой строке :
Цитата(tilin @  30.10.2009,  12:12 Найти цитируемый пост)
  float res = *(static_cast<float*>(b->GetResult()));

имхо Вы держите путь в сторону.


Это сообщение отредактировал(а) mes - 30.10.2009, 14:27


--------------------
PM MAIL WWW   Вверх
tilin
Дата 30.10.2009, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 23.9.2008

Репутация: нет
Всего: нет



Цитата(mes @  30.10.2009,  14:26 Найти цитируемый пост)
имхо Вы держите путь в сторону.

А вот если добавить сохранение результата в виде Варианта, тогда при получении значения руками преобразования типов делать не надо:
Код

float res = b->GetResult();

Только в моем варианте dynamic_cast пользуется, поэтому наверное стоит поучиться у boost::any  )

В общем вот так получается
Код

#include <memory>

using namespace std;

// ================================
class Variant
{
private:
    class IType
    {
    public:
        virtual ~IType()
        {
        }
    };
    typedef auto_ptr<IType> pIType;
    template <class T>
    class Type : public IType
    {
    public:
        T object;
        Type(T const& t)
        : object(t)
        {
        }
    };
    pIType itype;
public:
    template <class T>
    Variant& operator = (T const& t)
    {
        typedef Type<T> cType;
        itype = auto_ptr<cType>(new cType(t));
        return *this;
    }

    template <class T>
    operator T ()
    {
        typedef Type<T> cType;
        cType& type = dynamic_cast<cType&>(*itype);
        return type.object;
    }
};

class Base
{
public:
  virtual void Call() = 0;
  virtual Variant GetResult() = 0;
};

template <typename R, typename T, typename Arg1, typename Arg2>
class CallObject : public Base
{
  typedef R (T::*TFunc)(Arg1, Arg2);
  TFunc func;
  T* object;
  Variant result;
  Arg1 ar1;
  Arg2 ar2;

public:
  CallObject(TFunc _func, T* _object, Arg1 _ar1, Arg2 _ar2) 
      : func(_func), object(_object) , ar1(_ar1), ar2(_ar2) 
  { }

  void Call()
  {
      result = (object->*func)(ar1,ar2);
  }
  Variant GetResult()
  {
        return result;
  }
};



template <typename R, typename T, typename Arg1, typename Arg2>
inline Base* CreateCallObject(
  R (T::*func)(Arg1, Arg2), 
  T* object, 
  Arg1 ar1,
  Arg2 ar2) 
{
  return new CallObject<R, T, Arg1, Arg2>(func, object, ar1,ar2);
}

// ================================


class A
{
public:
    float Func(int d, float f)
    {
        return d+f;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    Base* b = CreateCallObject(&A::Func, &a, 12, (float)24);
    b->Call();
    float res = b->GetResult();

    return 0;
}

PM MAIL   Вверх
Страницы: (3) Все 1 2 [3] 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0648 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.