views:

50

answers:

1

I try to implement a template class which requires to have a signal member that depends on the template argument. My first idea was to realize it like the following:

template<class T>
class SignalClass 
{
    typedef boost::signals2::signal<void (T &)> OnReceive;

public:
    SignalClass(const OnReceive::slot_type &_slot)
    {
       m_onReceive.cnnect(_slot);
    }
    virtual SignalClass(){};

    void Send(T &_val)
    {
       m_onReceive(_val);
    }
private:
    OnReceive m_onReceive;
};

An that class should be used like:

class SignaledClass
{
public:
    SignaledClass(void)
    {   
       SignalClass<int>    var1(boost::bind(&SignaledClass::ReceiveINT, this));
       SignalClass<double> var2(boost::bind(&SignaledClass::ReceiveDOUBLE, this));
    }

   void ReceiveINT(int &_val)
   {
      ...
   }

   void ReceiveDOUBLE(double &_val)
   {
      ...
   }
}

(BTW: I know, that it makes no sense to create the SignalClass object just inside the constructor. It's just to understand my problem.)

It is important for me to realize a delegate-like concept with a template as signal parameter.

The problem is that the constructor code doesn't work.

But I found a solution.

If I additionally specify an additional typedef like

typedef typename OnReceive::slot_type slot_type;

and use that a parameter for the constructor, like

PushInputSlot(const slot_type& _slot);

the it works. But I have no real clue why.

I hope that somebody can help me.

Thanx, Frank

P.S.: I'm new on stackoverflow thats why I'm not familiar with the rules here. Hope I've done everything in the right way... ;-)....

A: 

Here is the reason why adding typename (either directly in the constructor argument or in an additional typedef) works:

First, the type OnReceive is a so-called "dependent type", because it depend on the type of the template parameter.

Then, templates are processed in two stages in the compiler: The first stage is when the compiler encounters the source text for the template and the second stage is when the template is actually instantiated. During the first stage of processing, the compiler will (should) try to validate as far as possible that the template definition is correct, but it runs into a problem when it comes to dependent types. Because a dependent type depends on the template parameters, the compiler does not know what the actual type will look like.
In particular, when accessing a member with the :: operator, the compiler needs some help deciding if the member is expected to refer to a member-type (typedef or nested class) or a non-type member (a variable, enum, etc.). This can be resolved by adding typename before the (full) type-name if you know that it should refer to a type.
The other place where the compiler might have a problem is differentiating between a member-template and a non-template member involved in a less-than comparison. This is resolved by adding the keyword template before the name of the member-template (immediately after the operator).

Bart van Ingen Schenau
Thank's for that information. It's the perfect answer.