Click here to Skip to main content
16,017,488 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
I would like to use variadic templates to help solve an issue using va-args. Basically, I want to call a singular function, pass into the function a "command" along with a variable list of arguments, then dispatch the arguments to another function.

I've implemented this using tried and true (but not type safe) va_list. Here's an attempt I made at doing this using variadic templates. The example doesn't compile below as you will quickly find out why...

C++
#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;
    }


Does anyone have an idea on how I can modify this function to use variadic templates correctly?
Posted
Updated 11-Sep-14 0:18am
v2
Comments
Stefan_Lang 11-Sep-14 6:27am    
This looks like it should work, but I have no compiler around to test it. Have you checked your compiler supports variadic templates? E. g. in VisualStudio it has only been added in late 2012.

1 solution

I presume the problem you are having here is that you are getting an error along the lines of cmd0 does not take 5 arguments?

This is because the function created as a result of the DispatchCommand(CMD_TWO, 5, 6, 7, 8, 9) is creating code that expects to call cmd0 (and cmd1) with all 5 arguments, if the cmd == CMD_ZERO. Remember that templates are compile time, not runtime.

If static_if was available, then that might be a solution, instead of the switch conditions. However, I don't believe it is implemented by any compiler and debate still rages (AFAIK) about it's use / support / standardisation.

However, another solution would be with partially specialized template classes (template functions cannot be partially specialized), although this seems like an aweful lot of code for what you are trying to achieve :) ...


C++
template<int>
class Dispatcher
{
public:
    template <typename... Args>
    static int exec(Args... args) {
        return -1;
    }
};

template<>
class Dispatcher<CMD_ZERO>
{
public:
    template <typename... Args>
    static int exec(Args... args) {
        cmd0(args...);
        return 0;
    }
};

template<>
class Dispatcher<CMD_ONE>
{
public:
    template <typename... Args>
    static int exec(Args... args) {
        cmd1(args...);
        return 0;
    }
};

template <int _Cmd, typename... Args >
int DispatchCommand(Args... args)
{
    return Dispatcher<_Cmd>::exec(args...);
}


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


Of course, this only works if the template parameters to DispatchCommand are compile time constants..... I hope this is of some help ?
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900