使用模板定义多个函数的 C++ 通用方法

C++ generic way to define multiple functions with a template

在C++中是否可以根据提供的模板参数的数量来定义多个方法?类似于可变参数函数的工作原理?

有我能做的功能

template <class ...Args>
struct VariadicFunctionCallback {
    typedef std::function<void(std::shared_ptr<Args>...)> variadic;
};

但我想知道的是我是否可以做类似的事情但创建多个函数而不是多个参数

template <class ...FunctionArg>
class Example {
     void Function(FunctionArg)...
}

然后我可以做类似

的事情
template <>
class Example<int, float> {
    void Function(int i) {
        ...
    }

    void Function(float f) {
        ...
    }
}

如果可能的话,与我当前的设置相比有什么优势

template<class EventType>
class EventHandler {
public:
    void HandleEvent(const std::shared_ptr<EventType>& event) {
    }
};

class ExampleEvent : public Event<ExampleEvent> {

};

class ExampleHandler : public EventHandler<ExampleHandler>, EventHandler<Events::ShutdownEvent> {
public:
    void HandleEvent(const std::shared_ptr<ExampleEvent> &event);

    void HandleEvent(const std::shared_ptr<Events::ShutdownEvent> &event);
};

--编辑-- 如果这两种解决方案,我最终得到了混合。 它可能不是最好的,我会继续尝试并加班改进它。

template <class EventType>
class BaseEventHandler {
public:
    EventIdentifier GetIdentifier() const {
        return EventType::GetIdentifier();
    }

    virtual void HandleEvent(const std::shared_ptr<EventType> &event) = 0;
};

template<class EventType, class ...EventTypes>
class EventHandler: public BaseEventHandler<EventTypes>... {

};

然后允许我做

class EventListener: public EventHandler<ShutdownEvent, MousePosEvent, WindowCloseRequestEvent> {
    void HandleEvent(const std::shared_ptr<ShutdownEvent> &event);
    void HandleEvent(const std::shared_ptr<MousePosEvent> &event);
    void HandleEvent(const std::shared_ptr<WindowCloseRequestEvent> &event);
}

我想你可以使 Example 成为一种递归自继承 class;像

    template <typename ...>
    struct Example
     {
       // dummy Function() to end the recursion
       void Function ()
        { }
     };

    template <typename T0, typename ... Ts>
    struct Example<T0, Ts...> : public Example<Ts...>
     {
       using Example<Ts...>::Function;

       void Function (T0 const &)
        { };
     };

所以你可以这样写

int main ()
 {
   Example<int, long, float>  e0;

   e0.Function(0);
   e0.Function(0L);
   e0.Function(0.0f);
 }

-- 编辑--

OP 询问

Could a specialisation then be preformed on top of this?

你的意思如下?

template <typename ...>
struct Example
 {
   // dummy Function() to end the recursion
   void Function ()
    { }
 };

template <typename T0, typename ... Ts>
struct Example<T0, Ts...> : public Example<Ts...>
 {
   using Example<Ts...>::Function;

   void Function (T0 const &)
    { };
 };

template <typename ... Ts>
struct Example<float, Ts...> : public Example<Ts...>
 {
   void FunctionFloat (float const &)
    { };
 };

int main ()
 {
   Example<int, long, float>  e0;

   e0.Function(0);
   e0.Function(0L);
   e0.FunctionFloat(0.0f);
   //e0.Function(0.0f); // compilation error
 }

,差不多

我们从一个class开始,它使用递归继承来实现我们的功能。在我的例子中,我选择了 operator(),并且我使用可变参数 using 声明将所有 children operator() 纳入范围:

namespace detail{
    template<class T, class... U>
    struct ExampleImpl : ExampleImpl<U>...{
        using ExampleImpl<U>::operator()...;
        void operator()(T _arg){/*...*/}
    };
}

我的回答与 max66 的不同之处在于,我们将使用此 ExampleImpl class 来 compose 我们的 Example class:

template<class... T>
class Example
{
public:
    template <class U>
    void Function(U arg)
    {
        impl(arg);
    }
    
    void Function(float arg) 
    {
        /*Your specialization code*/
    }
private:
    detail::ExampleImpl<T...> impl;
};

我这样做有两个原因:

  1. 这种继承是一种 implementation-detail 并且是您想对客户隐藏的东西。
  2. *现在我们可以轻松地将我们的 Function 函数专门化为我们想要的任何类型,因为我们始终可以选择是否调用我们的 ExampleImpl 实例。

Demo

如果ExampleImpl需要使用你的Exampleclass的成员变量,那么你可以把ExampleImpl变成full-fledgedPIMPL class, or modify its constructor or operator() to accept additional arguments as a form of Dependency Injection ]

*您可以轻松地执行完整的 class 专业化,其中 float 是专业化中的模板参数之一,并定义您自己的 Function。或者您可以使用 tag dispatching 的形式来隐藏 float 版本,除非它在模板类型列表中。

Tag dispatch demonstration