Search code examples
c++c++11templatesparameter-pack

extracting a template parameter pack with different types into a vector of doubles produces warnings


I am trying to convert a load of classes that are basically the same but take different number of parameters into a single template class. So I have create a template class example (not real code - just for example):

// The template type
template<typename... Args>
class tester_template
{
public:
    void process(Args... args)
    {
        // Create a vector to put the args into. use double since that can hold all of the types
        // that I am using (well enough for me anyway). But I get a lot of "narrowing" warnings
        // this is understandable, but I want to have no warnings (some sort of cast on a 
        // parameter pack??)
        std::vector<double> args_vect = {args...};
        for (auto arg : args_vect)
        {
            std::cout << arg << " ";
        }
        std::cout << std::endl;
    };
};

I run this like:

// Same with one template class
tester_template<double> template1;
tester_template<int, int> template2;
tester_template<int, int, int> template3;
tester_template<float> template4;
tester_template<float, double, int> template5;

template1.process(1.123);           // ok
template2.process(2, 2);            // Warnings
template3.process(3, 2, 3);         // Warnings
template4.process(4.4f);            // Warnings 
template5.process(5.5f, 2.234, 3);  // Warnings

Full example here with warnings and with example of previous many classes that the template class replaces: https://rextester.com/RBEA68379

So I understand the error/warning message (basically I might lose data if I convert). But I want to inhibit the warnings - perhaps by casting. But I have not a clue how to do this with a parameter pack - maybe I am missing it, but I did not find it online.

Two question I guess:

  1. Can I cast (or other method that does not turn warnings off) this away?
  2. I am just trying to extract the parameter pack into a structure that I can iterate, is what I am doing sensible, or is there a better way?

Solution

  • Yes, you can cast the arguments easily:

    std::vector<double> args_vect = {static_cast<double>(args)...};
    

    and there are no warnings emitted.

    Here's a demo.

    As pointed out in the comments by @NathanOliver, if you just want to print all the variadic arguments, you could do:

    void process(Args... args)
    {
       ((std::cout << args << " "), ...);
       std::cout << std::endl;
    };
    

    Then you don't have to worry about conversions of any kind.

    Here's a demo.

    You can also use sizeof... to figure out the number of arguments passed in, and use that information to dispatch to functions that take a fixed number of parameters:

    void process1arg(double ) {}
    void process2arg(double , double ) {}
    void process3arg(double , double  , double ) {}
    
    void process(Args... args)
    {  
        ((std::cout << args << " "), ...);
        std::cout << std::endl;
    
        if constexpr (sizeof...(args) == 1)
           process1arg(args...);
        if constexpr (sizeof...(args) == 2)
           process2arg(args...);
        if constexpr (sizeof...(args) == 3)
           process3arg(args...);
    };
    

    Note that you need if constexpr and not regular if, since otherwise the code will not compile when the number of arguments don't match.

    Here's a demo.