0

The old way to make variadic function in C/C++ is using va_list, va_start, va_arg, va_end defined in cstdarg. C++11 comes with variadic function template syntax, but how to access the values?

//example
#include <iostream>
using namespace std;

template <typename... types>
void print(types... Params){
  //this is not working:
  long Param1 = Params[0];
  long Param2 = Params[1];
}

int main(){
  print(123, 456);
  print(123, "foobar");
}
Dee
  • 7,455
  • 6
  • 36
  • 70

2 Answers2

1

This a very simple (not disruptive) way to do it, although perhaps not optimal:

#include <iostream>
#include<tuple>
#include<cassert>

using namespace std;

template <typename... types>
void print(types... Params){
  long Param1 = std::get<0>(std::tie(Params...));
  long Param2 = std::get<1>(std::tie(Params...));
  assert(Param1 == 123 and Param2 == 456);
}
int main(){
  print(123, 456);
}

https://godbolt.org/z/V8VA0W

If all elements are of the same type (and assuming you can copy them):

#include <iostream>
#include<tuple>
#include<cassert>

using namespace std;

template <typename... types>
void print(types... Params){
  std::array<long, sizeof...(Params)> params = {Params...};
  long Size = params.size();
  long Param1 = params[0];
  long Param2 = params[1];
  assert(Size == 2 and Param1 == 123 and Param2 == 456);
}

int main(){
  print(123, 456);
}

It is not clear from your question but it looks like you want to print all the elements in the list, if you just want to do this then you can do it as follows (needs C++17, but you can do this with some work in c++11):

#include <iostream>

using namespace std;

template <typename... types>
void print(types... Params){
    std::cout << "number of elements: " << sizeof...(Params) << " ";
    ((std::cout << Params), ...);
}

int main(){
  print(123, 456);
}
alfC
  • 14,261
  • 4
  • 67
  • 118
  • tks, this is much greater than using C's var_list – Dee May 27 '19 at 02:25
  • uhm, yeah, but how to get the number of params passed in? – Dee May 27 '19 at 02:26
  • 1
    @datdinhquoc, ok, this simple question has many layers because this gets into the rabbit hole of template metaprogramming very quickly. If you stay in the realms of "single-type" list, then there are other work arounds. See the new version of the answer. – alfC May 27 '19 at 02:28
  • it should work with multiple param types, like print(123,"foobar"), etc. Is counting number of params difficult in this case? – Dee May 27 '19 at 02:30
  • 1
    @datdinhquoc, that is the easy part (`sizeof...(Params)`), the hard part is know what you do with different types. Of course you don't say it but it seems you want to pass it to `cout << Params...`. – alfC May 27 '19 at 02:34
  • im thinking of "auto Param = Params[Index]", then get typeid(Param).name(), and finally switch/case to process it – Dee May 27 '19 at 02:38
  • 1
    @datdinhquoc, sorry, but as you will see that apprach will quickly run out of steam. Metaprogramming is your only option to go further and too much to explain here. – alfC May 27 '19 at 02:40
  • 1
    If you want to stay within simple tools, take a look at `std::tuple`, `std::tie` and `std::appy` https://en.cppreference.com/w/cpp/utility/apply , you can do a lot with just that. – alfC May 27 '19 at 02:46
0

There's a solution using operator<< here: https://stackoverflow.com/a/5495309/5581893

But it's not actually a single function call, it's a series of calls to operator<<, and the function can't be in global scope, it must be a method in a type.

Dee
  • 7,455
  • 6
  • 36
  • 70