How does one do two type variadic expansion? Here is what I am trying to achieve:
#include <vector>
#include <iostream>
class test
{
public:
std::vector< std::pair< float, int > > vec;
template<typename... T1, typename... T2>
test( T1... one, T2... two )
{
(
[&](float first, int second)
{
vec.emplace_back( std::pair< float, int >( first, second ) );
std::cout << first << ", " << second << std::endl;
}( one, two ),
...
);
}
};
int main()
{
test t
{
1.f,
1,
2.f,
2,
3.f,
3
};
return 0;
}
test must be initialized exactly like in main. I'd like usage in the constructor of test to remain similar.
Here is a working concept with va_list. Unfortunately, I need to pass a count for the parameters or I need to pass a magic-number terminator (I opted for the magic-number terminator).
#include <cstdarg>
#include <iostream>
#include <vector>
constexpr int END_OBJECT = 890123; // magic number
class test {
public:
std::vector<std::pair<int, double>> vec;
enum { is_name, is_data, is_max };
test(char ch, ...) {
std::pair<int, double> buf;
va_list b;
va_start(b, ch);
for (int i = 0;; i++) {
auto is = i % is_max;
if (is == is_name) {
if ( (buf.first = va_arg(b, int)) == END_OBJECT )
break;
} else if (is == is_data) {
buf.second = va_arg(b, double);
vec.emplace_back(buf);
}
}
va_end(b);
std::cout << ch << std::endl;
for (auto &x : vec)
std::cout << '\t' << x.first << ", " << x.second << std::endl;
}
};
int main() {
test t
{
'x',
1,
2.0,
3,
4.0,
5,
6.0,
END_OBJECT
};
return 0;
}
I'd like a more modern version of this using pack-expansion.
It's funny how this is basically FizzBuzz with template arguments and it's actually a nice challenge.
The easiest way in C++14 I could come up with is to use std::index_sequence. https://godbolt.org/z/dm3F9u
#include <vector>
#include <utility>
#include <tuple>
template <typename... TArgs, size_t... Is>
std::vector<std::pair<float, int>> pair_off(std::tuple<TArgs...> args, std::index_sequence<Is...>) {
return std::vector<std::pair<float, int>> { std::make_pair(std::get<(Is << 1)>(args), std::get<((Is << 1) + 1)>(args))... };
}
template <typename... TArgs>
std::vector<std::pair<float, int>> pair_off(TArgs&&... args) {
return pair_off(std::forward_as_tuple(std::forward<TArgs>(args)...), std::make_index_sequence<(sizeof...(TArgs) >> 1)>{});
}
std::vector<std::pair<float, int>> test() {
return pair_off(1.1f, 1, 2.2f, 2, 3.3f, 3);
}
Basically, first you pack the arguments into a tuple. Then you make an index sequence half the size of the argument list. Then you expand that index sequence, passing it into std::get.
What that does is the template equivalent of:
for (int i=0; i<list.size()/2; i++) {
output.push_back( std::make_pair(list[i*2], list[i*2+1]) );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With