在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);
}
答案 0 :(得分:8)
我想你可以让Example
成为一种递归的自我继承类;
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问
然后可以在此基础上进行专业化吗?
你的意思是如下吗?
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
}
答案 1 :(得分:2)
This answer start's with max66's answer,或多或少
我们从一个使用递归继承来实现我们的函数的类开始。就我而言,我选择了operator()
,并使用了一个变量使用声明来将所有孩子operator()
纳入范围:
namespace detail{
template<class T, class... U>
struct ExampleImpl : ExampleImpl<U>...{
using ExampleImpl<U>::operator()...;
void operator()(T _arg){/*...*/}
};
}
我的回答与max66相反,我们会使用此ExampleImpl
类来撰写我们的Example
类:
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;
};
我这样做有两个原因:
Function
函数专门用于我们想要的任何类型,因为我们总是可以选择是否调用我们的ExampleImpl
实例。如果ExampleImpl
需要使用Example
类的成员变量,那么您可以将ExampleImpl
转换为完整的PIMPL类,或者修改其构造函数或operator()
以Dependency Injection
*您可以轻松执行全班专精,其中float
是专业化中的模板参数之一,并定义您自己的Function
。或者您可以使用tag dispatching形式隐藏float
版本,除非它位于模板类型列表中。