0

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?
code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • 2
    Cast just like you normally would: `{static_cast(args)...}` – NathanOliver May 19 '20 at 20:13
  • 3
    *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?* Depends what you want to do. For instace, if you just wanted to print all of the parameters you can use `((std::cout << arg << " "), ...);` – NathanOliver May 19 '20 at 20:16
  • @NathanOliver - soooo simple! - I think I was just too scared to even try - thanks, although for some reason I would have though to put the brackets around the `(args...)` - which I can see is wrong : ) – code_fodder May 19 '20 at 20:18
  • @NathanOliver I want to count the number of args and pass them into a specific function which takes specific number of args based on another template type X (e.g. `typename X`) - but I did not want to muddy the minimal example :o – code_fodder May 19 '20 at 20:20
  • No worries. To get the count of the parameters, use `sizeof...(args)`/`sizeof...(Args)` and that will give you the number are element in the parameter pack – NathanOliver May 19 '20 at 20:22
  • @NathanOliver sweet! - is there a way to iterate the arguments (instead of sticking them into a vector)? - also feel free to put all this into an answer :) – code_fodder May 19 '20 at 20:23

1 Answers1

2

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.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • thanks! - as mentioned to Nathan - it looks so obvious now :o – code_fodder May 19 '20 at 20:21
  • No worries. Everything becomes obvious when you get used to it :) – cigien May 19 '20 at 20:23
  • Added @NathanOliver's alternative to the answer as well, with a demo. – cigien May 19 '20 at 20:25
  • thanks so much, did you see my last comment? I actually don't just want to print them out, I want to count the parameters and then also pass the parameters to a function that takes a specific number of parameters (so I can't pass as a parameter pack)... possible? – code_fodder May 19 '20 at 20:28
  • Sure, added a demonstration of that as well. – cigien May 19 '20 at 20:34
  • oh wow... I did not know you could just pass the args list directly into a function that takes set parameters!... (cuz that would have been my next question on SO). – code_fodder May 19 '20 at 20:42
  • Aah, good, you don't need to bother now :) Note that you can only pass the `args...` in a constexpr if context though, otherwise it won't compile. – cigien May 19 '20 at 20:43
  • Sorry, I did not quite understand your last comment. I passed it to a normal member function with non-const params. What did you mean about consexpr's? – code_fodder May 19 '20 at 20:47
  • Note the `if constexpr (sizeof...(args)`. If you remove the `constexpr` there, it won't compile. – cigien May 19 '20 at 20:48