Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过模板的侦听器模式,如何在不指定模板参数的情况下使用模板化类?c++;_C++_Templates_Listener - Fatal编程技术网

C++ 通过模板的侦听器模式,如何在不指定模板参数的情况下使用模板化类?c++;

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);

我想通过模板实现Receiver/Publisher类。我不确定模板是否是最好的。然而,到目前为止,我得到的是:

#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::向量侦听器;
};

您可能想看看,一些相同的原则可能适用。您的方法的主要问题是,您认为所有侦听器类都必须是管道,而实际上它们只需要是“接收端”。您可能应该定义一个只携带“侦听”的超类是
管道类的一部分(因此后者将继承它)。或者你有一个很好的理由来选择这种设计吗?实际上我提出了一个类似的解决方案。我发现在我的例子中,有一个“提供者”和一个“侦听器”确实更有意义,其中监听器将被继承,提供程序将用作类成员,这样一个对象可以向监听器提供多个不同的消息。