C++ 通过模板的侦听器模式,如何在不指定模板参数的情况下使用模板化类?c++;
我想通过模板实现Receiver/Publisher类。我不确定模板是否是最好的。然而,到目前为止,我得到的是:C++ 通过模板的侦听器模式,如何在不指定模板参数的情况下使用模板化类?c++;,c++,templates,listener,C++,Templates,Listener,我想通过模板实现Receiver/Publisher类。我不确定模板是否是最好的。然而,到目前为止,我得到的是: #include <vector> template <typename InType,typename OutType> class Pipe { public: void addListener(Pipe<OutType,???> l){ listener.push_back(l);
#include <vector>
template <typename InType,typename OutType> class Pipe {
public:
void addListener(Pipe<OutType,???> l){
listener.push_back(l);
}
virtual OutType process(InType)=0;
void Fill(InType value){
OutType outValue = process(value);
for (int i=0;i<listener.size();i++){
listener[i]->Fill(outValue);
}
}
private:
vector<Pipe<OutType,???>*> listener;
};
#包括
模板类管道{
公众:
void addListener(管道l){
监听器。推回(l);
}
虚拟输出类型进程(输入类型)=0;
空白填充(InType值){
OutType outValue=过程(值);
对于(int i=0;iFill(outValue);
}
}
私人:
向量监听器;
};
管道应该允许监听器具有不同的输出类型。实际上,它不需要知道监听器的输出类型,就像进程()一样由侦听器调用。但是,我必须输入一个模板参数。我的方法是否有问题?或者是否有方法避免指定侦听器的输出类型?您可以使管道
继承一个公共基类,这仅取决于InType
:
template <typename InType>
class PipeBase {
public:
virtual ~PipeBase() = default;
virtual void Fill(InType value) = 0;
};
template <typename InType, typename OutType>
class Pipe : public PipeBase<InType> {
public:
void addListener(PipeBase<OutType>* l){
listener.push_back(l);
}
void Fill(InType value) { ... }
private:
std::vector<PipeBase<OutType>*> listener;
};
模板
类管道基{
公众:
virtual~PipeBase()=默认值;
虚拟空白填充(InType值)=0;
};
模板
管道类别:公共管道基础{
公众:
void addListener(PipeBase*l){
监听器。推回(l);
}
空白填充(InType值){…}
私人:
向量监听器;
};
您困惑的根源是将监听器的概念混为一谈,即通知事件的监听器和管道-通知事件的监听器执行一些处理,然后将处理结果通知一组监听器。在这个模型中,管道是监听器,但监听器不一定是管道。 我建议您(1)允许任何可以接受
OutType
的可调用对象作为侦听器,(2)通过操作符()使用管道
接受输入
因此它是InType
的有效侦听器。然后,您可以使用std::function
删除侦听器的类型,在执行此操作时,使用std::function
删除转换函数的类型:
template <typename InType, typename OutType>
class Pipe {
public:
Pipe(std::function<OutType(InType)> transform) :
transform_(std::move(transform)) {}
// For lvalues, return reference to *this for chaining.
Pipe& addListener(std::function<void(OutType)> f) & {
listeners_.push_back(std::move(f));
return *this;
}
// For rvalues, return *this by value for chaining.
Pipe addListener(std::function<void(OutType)> f) && {
listeners_.push_back(std::move(f));
return std::move(*this);
}
void operator() (InType value) {
const auto outValue = transform_(std::move(value));
for (auto& listener : listeners_) {
listener(outValue);
}
}
private:
std::function<OutType(InType)> transform_;
std::vector<std::function<void(OutType)>> listeners_;
};
模板
等级管道{
公众:
管道(标准::函数转换):
变换(std::move(transform)){
//对于左值,返回对*的引用以进行链接。
管道和addListener(标准::函数f)和{
监听器向后推(std::move(f));
归还*这个;
}
//对于右值,按链接的值返回*this。
管道addListener(标准::函数f)和{
监听器向后推(std::move(f));
返回标准::移动(*此);
}
void运算符()(InType值){
常量自动输出值=转换(标准::移动(值));
用于(自动侦听器:侦听器(&U){
监听器(输出值);
}
}
私人:
函数变换;
std::向量侦听器;
};
您可能想看看,一些相同的原则可能适用。您的方法的主要问题是,您认为所有侦听器类都必须是管道,而实际上它们只需要是“接收端”。您可能应该定义一个只携带“侦听”的超类是
管道类的一部分(因此后者将继承它)。或者你有一个很好的理由来选择这种设计吗?实际上我提出了一个类似的解决方案。我发现在我的例子中,有一个“提供者”和一个“侦听器”确实更有意义,其中监听器将被继承,提供程序将用作类成员,这样一个对象可以向监听器提供多个不同的消息。