我尝试实现一个模板类,它需要一个依赖于模板参数的信号成员。我的第一个想法是如下所示:
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;
};
该类应该像:
一样使用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)
{
...
}
}
(顺便说一下:我知道,在构造函数中创建SignalClass对象是没有意义的。只是为了理解我的问题。)
对我来说,重要的是要用模板作为信号参数来实现类似委托的概念。
问题是构造函数代码不起作用。
但我找到了解决方案。
如果我另外指定一个额外的typedef
喜欢
typedef typename OnReceive::slot_type slot_type;
并使用该构造函数的参数,如
PushInputSlot(const slot_type& _slot);
它有效。 但我没有真正的线索原因。
我希望有人可以帮助我。
感谢名单, 弗兰克
P.S。:我是stackoverflow的新手,这就是为什么我不熟悉这里的规则。希望我以正确的方式完成所有事情......; - )....
答案 0 :(得分:2)
这就是为什么添加typename
(直接在构造函数参数或其他typedef中)起作用的原因:
首先,类型OnReceive
是所谓的“依赖类型”,因为它取决于模板参数的类型。
然后,在编译器中分两个阶段处理模板:第一阶段是编译器遇到模板的源文本,第二阶段是模板实际实例化的时间。
在处理的第一阶段,编译器将(应该)尽可能地尝试验证模板定义是否正确,但是当涉及到依赖类型时它会遇到问题。因为依赖类型取决于模板参数,编译器不知道实际类型是什么样的
特别是,当使用::
运算符访问成员时,编译器需要一些帮助来决定成员是否应该引用成员类型(typedef或嵌套类)或非类型成员(变量,枚举等)。如果你知道它应该引用一个类型,可以通过在(完整)类型名称之前添加typename
来解决这个问题。
编译器可能存在问题的另一个地方是区分成员模板和参与小于比较的非模板成员。通过在成员模板的名称之前(紧跟在运算符之后)添加关键字template
来解决此问题。