2014-09-10 2 views
2

Я хотел бы использовать вариативные шаблоны, чтобы помочь решить проблему с помощью va-args. В принципе, я хочу назвать сингулярную функцию, передать в функцию «команду» вместе с переменным списком аргументов, а затем отправить аргументы другой функции.Диспетчер шаблонов Variadic

Я реализовал это, используя проверенный (но не безопасный тип) 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; 
} 

Кто-нибудь есть идеи о том, как я могу изменить эту функцию, чтобы правильно использовать VARIADIC шаблоны?

+0

Почему вы не используете обычную перегрузку функций? Определите функцию 'DispatchCommand', которая принимает 4 параметра, перегружает ее той, которая занимает пять и так далее. – dyp

+2

«COMMANDS cmd» известно во время компиляции? – Jarod42

+0

Возможно, это поможет: https://stackoverflow.com/a/25264850 – Deduplicator

ответ

0

Напишите код, который, учитывая указатель на функцию и набор аргументов, вызывает его с самым длинным префиксом этих аргументов, который работает.

template<class...>struct types{using 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 перекрыт, то вам придется использовать набор перегрузки техники.

0

Вы можете использовать следующее:

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

 Смежные вопросы

  • Нет связанных вопросов^_^