ПрограммированиеФорумОбщее

Делегат и аргументы функции

Страницы: 1 2 Следующая »
#0
19:46, 11 июля 2011

Нубо-шаблоно-программист здесь.
Есть что-то похожее на делегат:
 

class IDelegate
{
public:
    virtual void Call() = 0;

protected:
    IDelegate(){}
    virtual ~IDelegate(){}
};



template<typename T, typename P1>
class TypeDelegate   :   public IDelegate
{
    typedef void (T::*FuncPtr)(P1);

public:
    TypeDelegate(T * pObj, FuncPtr pFuncPtr, P1 iParam)
    :   m_pObject(pObj),
        m_pFunc(pFuncPtr),
        m_iParam(iParam)
    {
    }

    void Call()
    {
        (m_pObject->*m_pFunc)(m_iParam);
    }

private:
    T *         m_pObject;
    FuncPtr     m_pFunc;
    P1          m_iParam;
};

 
Использование:

class TestClass
{
public:
    void func(int n)
    {
    }
};


void main()
{
    TestClass * pTest = new TestClass();

    int nNum = 10;
    IDelegate * pD = new TypeDelegate<TestClass, int>(pTest, &TestClass::func, nNum);
    pD->Call();
}

 
Всё работает. Но мне очень сильно хочется избавиться от необходимости указывать типы аргументов для сохраняемой функции
IDelegate * pD = new TypeDelegate<TestClass, int>(pTest, &TestClass::func, nNum);
 
Как нибудь можно от них избавиться? Может как-нибудь через boost::any, или RTTI/typeid, или через еще один шаблон?
Это возможно?

#1
20:25, 11 июля 2011

0xdeadc0de

template< class T, class F, class Arg>
IDelegate* makeDelegate(T *pTest, F func, Arg nNum){
  return new TypeDelegate<T, Arg>(pTest, func, nNum);
  }

IDelegate * pD = makeDelegate(pTest, &TestClass::func, nNum);
#2
21:28, 11 июля 2011

Try
Не компилится.
 
Упрощенный вариант:

class TestClass
{
public:
    void func(int * pP)
    {
    }

    void func(int n)
    {
    }
};


template<class T, class F>
void makeDelegate(T * pObject, F func)
{
}

void main()
{
    TestClass * pTest = new TestClass();

    makeDelegate(pTest, &TestClass::func);
}

компилятор говорит:
error C2914: 'makeDelegate' : cannot deduce template argument as function argument is ambiguous
error C2784: 'void makeDelegate(T *,F)' : could not deduce template argument for 'T *' from 'TestClass *'
 
Почему компилятор не может распознать класс, я понятия не имею. Хотя в других примерах, которые я раскуриваю, такой код работает.
Если задать руками явно:

makeDelegate<TestClass>(pTest, &TestClass::func);

, то финт срабатывает, но на втором аргументе новый затык:
error C2914: 'makeDelegate' : cannot deduce template argument as function argument is ambiguous
error C2784: 'void makeDelegate(T *,F)' : could not deduce template argument for 'overloaded function type' from 'overloaded function type'
see declaration of 'makeDelegate'
 
Здесь у меня знаний не хватает. Что это, и почему оно не нравится компилятору?

#3
21:38, 11 июля 2011

0xdeadc0de
А, понятно. Он затыкается в неизвестность из-за двух функций с одинаковым именем у класса TestClass.
Курю дальше.

#4
22:52, 11 июля 2011
#include <functional>
#include <iostream>
using namespace std;

class TestClass {
public:
  void foo() {
    cout << "Blah" << endl;
  }
};

int main() {
  std::function<void(TestClass*)> func = &TestClass::foo;


  TestClass tc;
  func(&tc);

  return 0;
}

Я тоже пытался так велосипедить, благо мне объяснили что к чему:)

А твой делегат лучше выкинь нафиг...

#5
23:06, 11 июля 2011

bazhenovc
Мне не подходит такая штука. Как не подходят boost::function, boost::signals и прочие такие же вещи.
Мне нужен не совсем делегат, а нечто, что могло бы сохранить в себе обьект, его функцию, её параметры, и быть "прозрачно"-одинаковым и не зависеть от используемого обьекта, его функции и параметров этой функции.

#6
23:31, 11 июля 2011

0xdeadc0de

#include <functional>
#include <iostream>
using namespace std;

class TestClass {
public:
  void foo(int a) {
    cout << "Blah" << endl;
  }

  void bar() {
    cout << "Moo" << endl;
  }
};

template <typename T, typename R, typename ...Args>
struct Delegate {
    T* ptr;
    std::function<R(T*, Args... args)> func;

    Delegate() {}

    Delegate(const Delegate& other) {
        ptr = other.ptr;
        func = other.func;
    }

    void call(Args... args) {
        if (func && ptr)
            func(ptr, std::forward<Args>(args)...);
    }
};

#define MAKE_DELEGATE(X, T, F) {X.ptr = T; X.func = F;}

int main() {

  TestClass tc;

  Delegate<TestClass, void, int> dlg1;
  MAKE_DELEGATE(dlg1, &tc, &TestClass::foo);
  dlg1.call(42);

  Delegate<TestClass, void> dlg2;
  MAKE_DELEGATE(dlg2, &tc, &TestClass::bar);
  dlg2.call();

  return 0;
}

Самому подумать лениво? :)

EDIT: А аргументы можно сложить в контейнер с Variant`ами, типа вот такого

#7
23:43, 11 июля 2011

bazhenovc
Можно считать, что я работаю с темплейтами первую неделю за всю жизнь. (Учитывая, сколько я уже себе нервов вытрепал, я бы хотел, что бы эта неделя никогда не начиналась)
 
Что такое "typename ...Args", в частности "..."?
Это не из нового стандарта (гугл подозрительно часто упомянает c++0x)?
Если да - мне не подходит.

#8
23:45, 11 июля 2011

0xdeadc0de
Вариадические шаблоны.
Из нового. Можно сделать и без этого, но тогда прийдётся хардкодить делегаты по кол-ву аргументов, что не есть гуд...

#9
0:08, 12 июля 2011

0xdeadc0de

#include <iostream>
using namespace std;

#include "Variant.hh"

class TestClass {
public:
  void foo() {
    cout << "Blah" << endl;
  }

  void bar() {
    cout << "Moo" << endl;
  }
};

struct DelegateBase {
  virtual void call() = 0;

  virtual ~DelegateBase() {}

  Variant obj;
  Variant func;
};

template <typename T, typename F>
struct Delegate : public DelegateBase {

  Delegate(T* object, F function) {
    obj = object;
    func = function;
  }

  virtual void call() {
    T* self = obj.toValue<T*>();
    auto real_func = func.toValue<F>();
    (self->*real_func)();
  }

};

int main() {

  TestClass tc;

  DelegateBase* dlg = new Delegate<TestClass, typeof(&TestClass::bar)>(&tc, &TestClass::bar);
  dlg->call();
  delete dlg;

  dlg = new Delegate<TestClass, typeof(&TestClass::foo)>(&tc, &TestClass::foo);
  dlg->call();
  delete dlg;

  return 0;
}

Вот так должно сработать. Если нужны аргументы - можно сделать по аналогии.

#10
0:25, 12 июля 2011

bazhenovc

// C++0x, gcc
#include <string>
#include <iostream>
#include <vector>

#include <typeinfo>

template< class ...Args>
class Signal{
  public:
    Signal(){
      }

    Signal( const Signal& s ){
      *this = s;
      }

    Signal( const Signal && s ){
      data = s.data;
      s.data.clear();
      }

    ~Signal(){
      disconnectAll();
      }

    Signal& operator = ( const Signal &s ){
      disconnectAll();
      data.resize( s.data.size() );

      for(decltype( data.size() ) i = 0; i<data.size(); ++i)
        data[i] = s.data[i]->clone();

      return *this;
      }

    void disconnectAll(){
      for(auto i=data.begin(); i!=data.end(); ++i)
        delete (*i);
      }

    template< class T >
    void connect(T *t, void (T::*f)( Args... ) ){
      disconnect(t, f);
      data.push_back( new Data<T>(t, f) );
      }

    template< class T >
    void disconnect(T *t, void (T::*f)( Args... ) ){
      for( decltype( data.size() ) i = 0; i<data.size(); ){
        if( data[i]->cmp( typeid(t), typeid(f) ) ){
          delete data[i];
          data[i] = data.back();
          data.pop_back();
          } else {
          ++i;
          }

        }
      }

    void emit( Args... a ){
      for(auto i=data.begin(); i!=data.end(); ++i)
        (*i)->call( a... );
      }

  private:


    class IData{
      public:
        virtual ~IData(){}
        virtual void call( Args... ) = 0;
        virtual bool cmp( const std::type_info& t,
                          const std::type_info& f ) = 0;
        virtual IData* clone() const = 0;
      };

    template< class T >
    class Data:public IData{
      public:
        Data( T* t, void (T::*f)( Args... ) ){
          obj  = t;
          func = f;
          }

        void call( Args... a ){
          (obj->*func)( a... );
          }

        bool cmp( const std::type_info& t, const std::type_info& f ){
          return t==typeid( obj  ) &&
                 f==typeid( func );
          }

        IData* clone() const{
          return new Data<T>(obj, func);
          }

        T* obj;
        void (T::*func)( Args... );
      };

    std::vector<IData*> data;
  };

// Использование

class B{
  public:
    void foo(int x, float y){
      std::cout << "B::foo "<< x<<" " <<y << std::endl;
      }
  };

class A{
  public:
    void foo(int x, float y){
      std::cout << "A::foo "<< x<<" " <<y << std::endl;
      }
  };

Signal<int, float> func( Signal<int, float> foo ){
  foo.emit(3, 3.14);
  return foo;
  }

int main(){
  A a;
  B b;

  Signal<int, float> foo;
  foo.connect(&b, &B::foo );
  foo.connect(&a, &A::foo );

  foo.emit(1, 1.1);

  foo.disconnect( &b, &B::foo );

  foo.emit(2, 2.2);

  func(foo).emit(4, 4.4);

  return 0;
  }


// Вывод программы
B::foo 1 1.1
A::foo 1 1.1
A::foo 2 2.2
A::foo 3 3.14
A::foo 4 4.4
#11
0:26, 12 июля 2011

bazhenovc
Variant.hh - это что?
Путем перебора и осмысливания я пришел к выводу, что это не опечатка бустовского variant.hpp, не std-шная вещь, не Поисково-спасательный вертолёт HH-43 Huskie, и не std/variant.d из D.

#12
0:30, 12 июля 2011

Try
EDIT:

Теперь сделай

Signal<int, float> foo;
  foo.connect(&b, &B::foo );
  foo.connect(&a, &A::foo );
 foo.emit(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);

И посмотрим, что будет;)


Не делай... Протупил, виноват:)

В любом случае, ТС просил без c++0x...

З.Ы.
Не говоря уже о том, что я терпеть не могу плюсовый RTTI

#13
0:32, 12 июля 2011

0xdeadc0de
прелюдия
завязка

#14
0:35, 12 июля 2011

bazhenovc
А, забыл. Спасибо, раскуриваю.

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.