可变参数模板调度程序
Posted
技术标签:
【中文标题】可变参数模板调度程序【英文标题】:Variadic Template Dispatcher 【发布时间】:2014-11-04 13:31:00 【问题描述】:我想使用可变参数模板来帮助解决使用 va-args 的问题。基本上,我想调用一个单数函数,将“命令”连同参数的变量列表传递给函数,然后将参数分派给另一个函数。
我已经使用经过验证的真实(但不是类型安全)va_list 实现了这一点。这是我使用可变参数模板进行的尝试。下面的示例无法编译,因为您很快就会发现原因...
#include <iostream>
using namespace std;
typedef enum cmd_t
CMD_ZERO,
CMD_ONE,
CMD_TWO,
COMMANDS;
int cmd0(double a, double b, double c)
cout << "cmd0 " << a << ", " << b << ", " << c << endl;
return 0;
int cmd1(int a, int b, int c)
cout << "cmd1 " << a << ", " << b << ", " << c << endl;
return 1;
template<typename... Args>
int DispatchCommand(COMMANDS cmd, Args... args)
int stat = 0;
switch (cmd)
case CMD_ZERO:
cmd0(args...);
break;
case CMD_ONE:
cmd1(args...);
break;
default:
stat = -1;
break;
return stat;
int main()
int stat;
stat = DispatchCommand(CMD_ZERO, 1, 3.141, 4);
stat = DispatchCommand(CMD_ONE, 5, 6, 7);
stat = DispatchCommand(CMD_TWO, 5, 6, 7, 8, 9);
system("pause");
return 0;
有人知道如何修改此函数以正确使用可变参数模板吗?
【问题讨论】:
为什么不使用普通的旧函数重载?定义一个函数DispatchCommand
,它接受4个参数,重载一个接受5个参数的函数,以此类推。
在编译时是否知道COMMANDS cmd
?
也许这会有所帮助:***.com/a/25264850
@Jarod42:必须提供正确的参数类型。因此,这个问题毫无意义。他试图“忘记”他将要使用哪个函数,然后再次推演,却无法正确推演。解决方案是首先不要忘记签名。
@Jarod40 - 是的,COMMANDS 枚举在编译时是已知的
【参考方案1】:
编写一些代码,给定一个函数指针和一组参数,使用这些参数中最长的前缀调用它。
template<class...>struct typesusing type=types;;
template<class types0, size_t N, class types1=types<>>
struct split;
template<class t00, class...t0s, size_t N, class...t1s>
struct split<types<t00,t0s...>,N,types<t1s...>>:
split<types<t0s...>,N-1,types<t1s...,t00>>
;
template<class...t0s, class...t1s>
struct split<types<t0s...>,0,types<t1s...>>
using right=types<t0s...>;
using left=types<t1s...>;
;
template<class>using void_t=void;
template<class Sig,class=void>
struct valid_call:std::false_type;
template<class F, class...Args>
struct valid_call<F(Args...), void_t<
decltype( std::declval<F>()(std::declval<Args>()...) )
>>:std::true_type ;
template<class R, class types>
struct prefix_call;
template<class R, class...Args>
struct prefix_call<R, types<Args...>>
template<class F, class... Extra>
std::enable_if_t< valid_call<F(Args...)>::value, R >
operator()(R default, F f, Args&&...args, Extra&&...) const
return std::forward<F>(f)(args...);
template<class F, class... Extra>
std::enable_if_t< !valid_call<F(Args...)>::value, R >
operator()(R default, F f, Args&&...args, Extra&&...) const
return prefix_call<R, typename split<types<Args...>, sizeof...(Args)-1>::left>(
std::forward<R>(default), std::forward<F>(f), std::forward<Args>(args)...
);
;
template<class R>
struct prefix_call<R, types<>>
template<class F, class... Extra>
std::enable_if_t< valid_call<F()>::value, R >
operator()(R default, F f, Extra&&...) const
return std::forward<F>(f)();
template<class F, class... Extra>
std::enable_if_t< !valid_call<F()>::value, R >
operator()(R default, F f, Extra&&...) const
return std::forward<R>(default);
;
以上代码可能有错别字。
template<typename... Args>
int DispatchCommand(COMMANDS cmd, Args... args)
int stat = 0;
switch (cmd)
case CMD_ZERO:
stat = prefix_call<int, Args...>(-1, cmd0, std::forward<Args>(args)...);
break;
case CMD_ONE:
stat = prefix_call<int, Args...>(-1, cmd1, std::forward<Args>(args)...);
break;
default:
stat = -1;
break;
return stat;
如果cmd0
或cmd1
被覆盖,则必须使用重载集技术。
【讨论】:
【参考方案2】:您可以使用以下内容:
template <COMMANDS cmd> struct command
template <typename ... Args>
int operator() (Args&&...) const return -1;
;
template <> struct command<CMD_ZERO>
int operator()(double a, double b, double c) const
std::cout << "cmd0 " << a << ", " << b << ", " << c << std::endl;
return 0;
;
template <> struct command<CMD_ONE>
int operator()(int a, int b, int c) const
std::cout << "cmd1 " << a << ", " << b << ", " << c << std::endl;
return 1;
;
template <COMMANDS cmd, typename... Args> int DispatchCommand(Args&&... args)
return command<cmd>()(std::forward<Args>(args)...);
然后像这样使用它:
DispatchCommand<CMD_ZERO>(1., 3.141, 4.);
DispatchCommand<CMD_ONE>(5, 6, 7);
DispatchCommand<CMD_TWO>(5, 6, 7, 8, 9);
Live example
但直接使用不同的函数似乎更简单:
cmd0(1., 3.141, 4.);
cmd1(5, 6, 7);
【讨论】:
以上是关于可变参数模板调度程序的主要内容,如果未能解决你的问题,请参考以下文章