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!
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...`
}
};