Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::function and Signal/Slot system

I'm trying to create a simple Signals/Slots system in C++ without boost but I've got some problems when I try to use it with parameters, here is my code :

My Signal class :

template <typename T> 
class Signal
{
private:
    typedef std::function<T> Slot;

public:
    Signal();

    void connect( Slot slot );
    void emit( T data );
    void emit();

private:    
    std::vector<Slot> slots;    
};

My Test class :

class Object
{
public:
    Object();
    void sayHello(  int i  );
};

So, I use my class like that :

Signal<void(int)> signal;
signal.connect( std::bind( &Object::sayHello, player, std::placeholders::_1 ) );
signal.emit( 0 );

I've got a warning in Signal.cpp : Candidate function not viable: no known conversion from 'void (*)(int)' to 'int' for 1st argument;

In this code :

template <typename T>
void Signal<T>::emit( T data )
{
    typename std::vector<Slot>::iterator i;
    Slot t;

    for( i = this->slots.begin(); i != this->slots.end(); i++ )
    {
        t = (*i);
        t( data );   // Here
    }
}

How can I solve that? If I want give an object or multiples parameters to my "emit" method, hoc can i do?

Thanks!

like image 712
Dono Avatar asked Nov 07 '12 20:11

Dono


People also ask

What is a signal slot C++?

A slot is called when a signal connected to it is emitted. Slots are normal C++ functions and can be called normally; their only special feature is that signals can be connected to them. A slot's arguments cannot have default values, and, like signals, it is rarely wise to use your own custom types for slot arguments.

How does signal and slot work?

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.


1 Answers

Picking three lines from your Signal class:

template <typename T> 
    // ...
    typedef std::function<T> Slot;
    // ...
    void emit( T data );

And the declaration of your signal:

Signal<void(int)> signal;

The answer should be pretty obvious: void emit(T) becomes void emit(void(*)(int)) (function types like void(int) transform to pointers when they are function parameters).

I'd simply recommend going the same way every class template that uses T<Signature> goes: partial specialization.

template<class Sig>
class Signal;

template<class R, class... Args>
class Signal<R(Args...)>{
  // ...
  typedef std::function<R(Args...)> Slot;
  // ...
  void emit(Args... args) const{
    // iterate over slots and call them, passing `args...`
  }
};
like image 162
Xeo Avatar answered Sep 24 '22 19:09

Xeo