如何通过模板传递函数?

时间:2018-06-25 19:04:41

标签: c++ c++11 templates

当前正在尝试为SDL项目实现事件处理程序。总体思路是,用户输入事件将通过Message对象进行处理,这些对象将能够携带具有不同签名的回调。目前,我拥有的是:

#pragma once
#include<functional>

#include"Entity.h"
#include"Enums.h"

typedef std::function<void(void)> VoidCallback;
typedef std::function<void(const Entity& entity)> EntityCallback;

template<typename Functor>
class Message
{
private:
    MessageType message;

public:
    Message(MessageType message, Functor callback) :message(message), callback(callback) {};
    ~Message();
};

但是,这种安排使得很难将不同类型的回调传递给不同的侦听器。当前的监听器实现是

#include"Message.h"

class Listener
{
public:
    virtual void onNotify(Message<>& event) = 0;
};

这会导致错误。解决此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

您不能具有模板虚拟功能

Can a C++ class member function template be virtual?

#include "Message.h"

class Listener
{
public:

    //you may use a template function as such
    template<class func>
    void onNotify(Message<func>& event) { /*must implement*/ }

    //or specialize for specific function calls
    virtual void onNotify(Message<some_known_func>& even) = 0;
};

如果您想使用具有类似虚拟功能的模板方法,可能会对研究CRTP感兴趣。 (CRTP使超类可以调用子类的方法)

答案 1 :(得分:1)

无法对虚拟功能进行模板化。

通过vtable调用虚拟函数,该{基本上是函数指针的数组。基类中的每个虚拟方法都占用虚拟表中的一个插槽。显然,虚拟表的大小需要在编译时就知道,因为它是对象定义的一部分。

class Base {
public:
    virtual void hello(){};
    virtual void bye(){};   
}

vtable可能如下所示:

  • 指向hello的指针。
  • 指向bye的指针。

因此vtable需要2个函数指针。

现在如果要hello()bye()进行模板化,我们如何创建一个vtable?

  • 指向hello<int>()的指针
  • 指向hello<char>()的指针。

我们无法预先知道模板化函数的所有变体,因此无法构建vtable。