Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Variadic template method specialization

I have some variadic template method, which looks like this:

    template<typename ... Args>
    void Invoke(const char* funcName, Args ... args) const;

    template<typename ... Args>
    void Invoke(const char* funcName, Args ... args) const
    {
        SPrimitive params[] = { args ... };
        SomeOtherInvoke(funcName, params, sizeof ... (Args));
    }

Here SPrimitive - just a simple struct with a constructor for any primitive type.

I want to make one more Invoke definition for some complex type. And here is my question: Is it possible to make variadic template method specialization in c++ 11/14 ? I mean something like this ( for simplicity lets my type will be int):

    template<int ... Args>
    void Invoke(const char* funcName, Args ... args)
    {
        int params[] = { args ... };
        SomeComplexInvoke(funcName, params, sizeof ... (Args));
    }

Here I want a specialization, which takes any parameters count of type int, so I can call it just like this:

    Invoke("method", 2, 4 ,9);
like image 505
Michael Avatar asked Aug 18 '16 08:08

Michael


1 Answers

As @Jarod42 mentioned, it should not be done with specialization. In your example you want something special if all argument types are int, so let's write a template which will check it:

template<typename ref, typename t, typename ...types>
struct all_same {
        static constexpr bool value = std::is_same<ref, t>::value && all_same<ref, types...>::value;
};

template<typename ref, typename t>
struct all_same<ref, t> {
        static constexpr bool value = std::is_same<ref, t>::value;
};

It checks whether first type argument is equal to all other type arguments. Then in Invoke we should select params type based on args... types:

template<typename ... Args>
void Invoke(const char* funcName, Args ... args)
{
    using params_type = typename std::conditional<all_same<int, Args...>::value, int, SPrimitive>::type;
    params_type params[] = { args ... };
    SomeOtherInvoke(funcName, params, sizeof ... (Args));
}

Now for the sake of demonstration let's define:

struct SPrimitive{
};

void SomeOtherInvoke(const char*, SPrimitive*, size_t) {
        std::cout << "Invoked for SPrimitive\n";
}

void SomeOtherInvoke(const char*, int*, size_t) {
        std::cout << "Invoked for int\n";
}

and call

Invoke("foo", SPrimitive());
Invoke("foo", SPrimitive(), SPrimitive());
Invoke("foo", 1, 2, 3, 4);

The output is:

Invoked for SPrimitive
Invoked for SPrimitive
Invoked for int

which is what you asked for.

like image 129
Sergey Avatar answered Oct 16 '22 19:10

Sergey