简体   繁体   中英

C++ Variadic Function Templates of Known Type

I'm currently trying to get my head around some of the things I can do with variadic template support. Let's say I have a function like this -

template <typename ... Args>
void foo(Args ... a)
{
    int len = sizeof...(tail);
    int vals[] = {a...};
    /* Rest of function */
}

/* Elsewhere */
foo(1, 2, 3, 4);

This code works because I assume beforehand that the arguments will be integers, but obviously will fail if I provide something else. If I know that the parameter packs will contain a particular type in advance, is there some way that I can do without the templating and have something like -

void foo(int ... a)

I have tried doing this, but the compiler gave an error about foo being a void field. I know that I can also access the parameters in the pack through recursion, but I'm not sure this will fix the problem that I have - namely I want to be able to take a variable number of arguments of the same type.

This should work:

void foo(int);

template<typename ...Args>
void foo(int first, Args... more)
{
   foo(first);
   foo(more...);
}

If you know the types before, you can use function overload withstd:initializer_list :

#include <initializer_list>
#include <iostream>

void foo( std::initializer_list<int> l )
{
    for ( auto el : l )
        // do something
}

void foo( std::initializer_list<float> l )
{
}

void foo( std::initializer_list<std::string> l )
{
}

int main()
{
    foo( {1, 2, 3, 4 } );
    foo( {1.1f, 2.1f, 3.1f, 4.1f } );
    foo( { "foo", "bar", "foo", "foo" } );
    return 0;
}

If you use Visual Studio 2012, you might need the Visual C++ Compiler November 2012 CTP .

EDIT : If you still want to use variadic template, you can do :

template <int ... Args>
void foo( )
{
    int len = sizeof...(Args);
    int vals[] = {Args...};
    // ...
}

// And

foo<1, 2, 3, 4>();

But you have to remember that it is not working with float and std::string for example : you will end with 'float': illegal type for non-type template parameter . float is not legal as a non-type template parameter , this is to do with precision, floating point numbers cannot be precisely represented, and the likelyhood of you referring to the same type can depend on how the number is represented.

I'm currently trying to get my head around some of the things I can do with variadic template support.

Assuming that you want to experiment with variadic templates, not find any solution to your problem, then I suggest taking a look at the code below:

#include <iostream>

template<int ...Values>
void foo2()
{
    int len = sizeof...(Values);
    int vals[] = {Values...};

    for (int i = 0; i < len; ++i)
    {
        std::cout << vals[i] << std::endl;
    }
}

int main()
{
    foo2<1, 2, 3, 4>();

    return 0;
}

The difference between foo2 and your foo is that you pass the parameters to foo at runtime, and to foo2 at compilation time, so for every parameter set you use, compiler will generate separate foo2 function body.

A variation of the top answer which will reject implicit conversion to int , if that is your preference:

#include <type_traits>

void foo(int);

template<typename Arg1, typename ...Args>
void foo(Arg1 first, Args... more)
{
   static_assert(std::is_same_v<Arg1, int>, "foo called with non-int argument");
   foo(first);
   foo(more...);
}

In most cases, there's no point using variadic templates with parameters pack of the same types, but in a c++11-enabled compiler would be:

#include <iostream>
#include <tuple>

template <typename ... Args>
void foo(Args ... args) {
    using type = typename std::tuple_element<0, std::tuple<Args...>>::type;
    const auto len = std::tuple_size<std::tuple<Args...>> {};
    type vals[] = {args...};

    for (size_t it = 0; it < len; ++it) {
        std::cout << vals[it] << std::endl;
    }
}

int32_t main(int argc, char** argv) {
    foo(1, 2);
    foo(1.1, 2.2);
    foo("1", "2");
    return EXIT_SUCCESS;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM