STD container inheritance - c++

I want to declare class which depends on 'mode' field works with different type of standard containers. How I can do that?!
class Container {
public:
Container(int8_t initMode);
void addPair(string name, int32_t number);
int8_t mode;
private:
std::_Container_base _container;
};
Container::Container(int8_t m) {
mode = m >= 0 && m <= 2 ? m : 0;
switch (mode) {
case 0:
//_container should be Map;
break;
case 1:
//_container should be Dictionary;
break;
case 2:
//_container should be HashMap;
break;
}
}

When you declare a variable of a certain type, the variable must be that type exactly. You can instead use polymorphism and make _container a std::_Container_base*, and then allocate it as whatever subclass of std::_Container_base you want via new.
I don't think std::_Container_base is portable, though, so you should consider using a union of the containers you want, then switch which one you use based on the mode.

You could use a variant, you wouldn't even need a mode attribute since std::holds_alternative<MapType>(_container) can give you that info.
template <class T>
class Container {
public:
private:
using Key = std::string;
std::variant<
std::map<Key,T>,
std::multimap<Key,T>,
std::unordered_map<Key,T>,
std::unordered_multimap<Key,T>> _container;
}
https://en.cppreference.com/w/cpp/utility/variant
More complete example:
#include <iostream>
#include <string>
#include <map>
#include <stdexcept>
#include <unordered_map>
#include <variant>
template <class T>
class Container {
public:
using Key = std::string;
template<class C> Container(const C& c) : _container(c) {}
template<class C> Container(C&& c) : _container(std::move(c)) {}
template<class C>
Container& operator=(const C& c) { _container = c; return *this; }
template<class C>
Container& operator=(C&& c) { _container = std::move(c); return *this; }
T getFirstElement(const Key& key) {
if (!hasKey(key)) throw std::runtime_error("No such key: " + key);
return std::visit([this, key](auto& cont){ return cont.find(key)->second; }, _container);
}
T getFirstElement(const Key& key, T or_value) noexcept {
if (!hasKey(key)) return or_value;
return getFirstElement(key);
}
bool hasKey(const Key& key) const {
return std::visit([this, key](auto& cont){ return cont.count(key); }, _container) > 0;
}
private:
std::variant<
std::map<Key,T>,
std::multimap<Key,T>,
std::unordered_map<Key,T>,
std::unordered_multimap<Key,T>> _container;
};
int main()
{
std::map<std::string, int> someMap {{"one", 1}, {"two", 2}};
std::unordered_map<std::string, int> someUmap {{"one", 11}, {"two", 22}};
Container<int> cont(someMap);
std::cout << cont.getFirstElement("two") << std::endl; // 2
cont = someUmap;
std::cout << cont.getFirstElement("two") << std::endl; // 22
return 0;
}

Related

Expand parameter pack into tuple with tuple_cat

Godbolt link: https://godbolt.org/z/18nseEn4G
I have a std::map of various types of vectors (cast to void*) and a T& get<T> method that gives me a reference to an element in one of the vectors in the map.
class Container {
public:
Container() {
auto v1 = new std::vector<int>({1, 2, 3, 4, 5});
auto v2 = new std::vector<char>({'a','b','c','d','e'});
auto v3 = new std::vector<double>({1.12, 2.34, 3.134, 4.51, 5.101});
items.insert({
std::type_index(typeid(std::vector<int>)),
reinterpret_cast<void*>(v1)
});
items.insert({
std::type_index(typeid(std::vector<char>)),
reinterpret_cast<void*>(v2)
});
items.insert({
std::type_index(typeid(std::vector<double>)),
reinterpret_cast<void*>(v3)
});
}
template<typename T>
T& get(int index) {
auto idx = std::type_index(typeid(std::vector<T>));
auto ptr = items.at(idx);
auto vec = reinterpret_cast<std::vector<T>*>(ptr);
return (*vec)[index];
}
private:
std::map<std::type_index, void*> items {};
};
I want to be able to use structured binding to get back references to 3 elements all at the same index but in difference vectors, but I'm not sure how to create a tuple with multiple calls to the T& get<T> method.
Something like this;
auto [a, b, c] = myContainer.get_all<int, char, double>(1); // get a reference to an int, a char, and a double from myContainer at index 1.
I'm currently trying to make use of repeated calls to T& get<T> for each parameter in a parameter pack, but I can't figure out the correct syntax.
template<typename... Ts>
auto get_all(int index) {
return std::tuple_cat<Ts...>(
std::make_tuple<Ts>(get<Ts>(index)...)
);
How could I make this work?
Here is a link to my current attempt:
https://godbolt.org/z/18nseEn4G
Alternatively, is there a "better way" to achieve this?
I would suggest using type erasure. Here is an example:
#include <vector>
#include <typeindex>
#include <memory>
#include <any>
#include <unordered_map>
#include <iostream>
#include <experimental/propagate_const>
// If no library implementation is availble, one may be copied from libstdc++
template<class T>
using propagate_const = std::experimental::propagate_const<T>;
class Container
{
public:
Container() {
std::unique_ptr<Eraser> v1{ static_cast<Eraser*>(new ErasedVector<int>(1, 2, 3, 4, 5)) };
std::unique_ptr<Eraser> v2{ static_cast<Eraser*>(new ErasedVector<char>('a','b','c','d','e')) };
std::unique_ptr<Eraser> v3{ static_cast<Eraser*>(new ErasedVector<double>(1.12, 2.34, 3.134, 4.51, 5.101)) };
items[std::type_index(typeid(int))] = std::move(v1);
items[std::type_index(typeid(char))] = std::move(v2);
items[std::type_index(typeid(double))] = std::move(v3);
}
template<typename... Ts>
std::tuple<Ts&...> get(size_t index)
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
template<typename... Ts, typename = std::enable_if_t<(std::is_const_v<Ts> && ...)>>
std::tuple<Ts&...> get(size_t index) const
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
private:
class Eraser
{
public:
virtual std::any operator[](size_t index) = 0;
virtual std::any operator[](size_t index) const = 0;
virtual ~Eraser() = default;
};
template <typename T>
class ErasedVector : public Eraser
{
public:
template <typename... Args>
ErasedVector(Args&&... args) :
data{ std::forward<Args>(args)... }
{
}
virtual std::any operator[](size_t index) override final
{
return std::reference_wrapper{ data[index] };
};
virtual std::any operator[](size_t index) const override final
{
return std::reference_wrapper{ data[index] };
}
private:
std::vector<T> data;
};
std::unordered_map<std::type_index, propagate_const<std::unique_ptr<Eraser>>> items;
};
It works properly on this example:
int main()
{
Container co;
auto [i0_0, c0_0, d0_0] = co.get<int, char, double>(0);
std::cout << i0_0 << ' ' << c0_0 << ' ' << d0_0 << '\n';
i0_0 = 3; // is a reference
d0_0 = 42; // is a reference
auto [i0_1, d0_1] = static_cast<const Container&>(co).get<const int, const double>(0); // works on const Container
std::cout << i0_1 << ' ' << d0_1; // original values modified
// i0_1 = 0xDEADBEEF; can be const too
}
And outputs:
1 a 1.12
3 42
Demo
Simply:
template<typename... Ts>
auto get_all(int index) {
return std::tuple<Ts&...>(get<Ts>(index)...);
}
Demo
You can use std::tie to take all of the "returns" from get<Ts>(index) can pack them into a tuple of references. That would look like
template<typename... Ts>
auto get_all(int index) {
return std::tie(get<Ts>(index)...);
}

An unordered_map that returns pairs of different types c++

I am trying to implement an std::unordered_map that returns pairs of either double, int or std::string. The keys for the map are std::strings. Below is what I have tried so far:
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <utility>
#include <vector>
// A base class for boundary class
class Boundbase {
public:
Boundbase(){};
virtual ~Boundbase(){};
};
// A different map of boundaries for each different data type
template <class dType>
class Boundary : public Boundbase {
std::pair<dType, dType> bpair;
public:
//Constructor
Boundary(const std::string &lbound,
const std::string &ubound) {
setbound(lbound, ubound);
};
//A method to set boundary pair
void setbound(const std::string &lbound,
const std::string &ubound);
// A method to get boundary pair
std::pair<dType, dType> getbound() {return bpair;}
};
// Class to hold the different boundaries
class Boundaries {
std::unordered_map<std::string, Boundbase*> bounds;
public:
//Constructor
Boundaries() {};
// A method to set boundary map
void setboundmap(std::unordered_map<std::string,
std::vector<std::string>> xtb);
// A template to get boundaries.
std::unordered_map<std::string, Boundbase*> getbounds()
{return bounds;}
};
// A method to set covariate boundary
template <class dType> void
Boundary<dType>::setbound(const std::string &lbound,
const std::string &ubound) {
dType val;
std::istringstream isa(lbound);
while(isa >> val) {
bpair.first = val;
}
std::istringstream isb(ubound);
while(isb >> val) {
bpair.second = val;
}
}
// A method to set boundary map
void Boundaries::setboundmap(std::unordered_map<std::string,
std::vector<std::string>> xtb) {
for(auto s : xtb) {
char type = s.second[1][0];
switch(type) {
case 'd': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<double>(
s.second[2], s.second[3]);
bounds.insert(opair);
}
break;
case 'i': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<int>(
s.second[2], s.second[3]);
bounds.insert(opair);
break;
}
case 'c': {
std::pair<std::string, Boundbase*> opair;
opair.first = s.first;
opair.second = new Boundary<std::string>(
s.second[2], s.second[2]);
bounds.insert(opair);
break;
}
}
}
}
This compiles ok using g++. When I try to run it though ( as follows):
int main() {
Data D;
Boundaries B;
std::ifstream iss("tphinit.txt");
D.read_lines(iss);
auto dbounds = D.get_xtypebound();
B.setboundmap(dbounds);
auto tbounds = B.getbounds();
auto sbound = tbounds["X1"];
std::cout << sbound->bpair.first << ","
<< sbound->bpair.second << std::endl;
}
I get 'class Boundbase' has no member named 'bpair' which is true because I am pointing to the base class and not the derived class. As far as I can tell, trying to get the derived member bpair requires that I use the visitor pattern. Now, it is clear that I am noob so when I had a look at different ways of doing this on SO I was a little in over my head (no reflection on the authors, just on my inexperience).
So my main question is: Is this the best and simplest way to go about this? I would like to avoid boost::variant if at all possible (mainly for the sake of purity: this cannot be that difficult). A sub-question is whether I have to use the visitor pattern or is there a better/simpler way to get the member pbair?
I will have to perform this lookup many times so I am hoping to make it as fast as possible but using the stl for the sake of simplicity.
Make your values std variants over the 3 types.
Failing that, boost variant.
Std and boost variant really are what you want. You'll end up implementing some subset of its implementation.
Failing that, find a tutorial on how to implement ones of them, or use std any. Failing that, dynamic casts around an otherwise useless wrapper type with a virtual dtor stored in a unique ptr, or do manual RTTI with try get methods.
This just gets increasingly ugly and/or inefficient however.
Boost variant, and std variant from it, was implemented for a reason, and that reason was solving the exact problem you are describing in an efficient manner.
#include <tuple>
#include <utility>
#include <string>
template<class...Ts>
struct destroy_helper {
std::tuple<Ts*...> data;
destroy_helper( std::tuple<Ts*...> d ):data(d){}
template<class T>
static void destroy(T* t){ t->~T(); }
template<std::size_t I>
void operator()(std::integral_constant<std::size_t, I>)const {
destroy( std::get<I>( data ) );
}
};
struct construct_helper {
template<class T, class...Args>
void operator()(T* target, Args&&...args)const {
::new( (void*)target ) T(std::forward<Args>(args)...);
}
};
template<std::size_t...Is>
struct indexes {};
template<std::size_t N, std::size_t...Is>
struct make_indexes:make_indexes<N-1, N-1, Is...> {};
template<std::size_t...Is>
struct make_indexes<0, Is...>{
using type=indexes<Is...>;
};
template<std::size_t N>
using make_indexes_t = typename make_indexes<N>::type;
template<class F>
void magic_switch( std::size_t i, indexes<>, F&& f ) {}
template<std::size_t I0, std::size_t...Is, class F>
void magic_switch( std::size_t i, indexes<I0,Is...>, F&& f )
{
if (i==I0) {
f( std::integral_constant<std::size_t, I0>{} );
return;
}
magic_switch( i, indexes<Is...>{}, std::forward<F>(f) );
}
template<class T0>
constexpr T0 max_of( T0 t0 ) {
return t0;
}
template<class T0, class T1, class...Ts>
constexpr T0 max_of( T0 t0, T1 t1, Ts... ts ) {
return (t1 > t0)?max_of(t1, ts...):max_of(t0, ts...);
}
template<class...Ts>
struct Variant{
using Data=typename std::aligned_storage< max_of(sizeof(Ts)...), max_of(alignof(Ts)...)>::type;
std::size_t m_index=-1;
Data m_data;
template<std::size_t I>
using alternative_t=typename std::tuple_element<I, std::tuple<Ts...>>::type;
using pointers=std::tuple<Ts*...>;
using cpointers=std::tuple<Ts const*...>;
template<class T> T& get(){ return *reinterpret_cast<T*>(&m_data); }
template<class T> T const& get() const { return *reinterpret_cast<T*>(&m_data); }
template<std::size_t I>
alternative_t<I>& get(){ return std::get<I>(get_pointers()); }
template<std::size_t I>
alternative_t<I> const& get()const{ return std::get<I>(get_pointers()); }
pointers get_pointers(){
return pointers( (Ts*)&m_data... );
}
cpointers get_pointers()const{
return cpointers( (Ts const*)&m_data... );
}
std::size_t alternative()const{return m_index;}
void destroy() {
if (m_index == -1)
return;
magic_switch(m_index, make_indexes_t<sizeof...(Ts)>{}, destroy_helper<Ts...>(get_pointers()));
}
template<std::size_t I, class...Args>
void emplace(Args&&...args) {
destroy();
construct_helper{}( std::get<I>(get_pointers()), std::forward<Args>(args)... );
m_index = I;
}
Variant()=default;
Variant(Variant const&)=delete;//todo
Variant&operator=(Variant const&)=delete;//todo
Variant(Variant &&)=delete;//todo
Variant&operator=(Variant &&)=delete;//todo
~Variant(){destroy();}
};
int main() {
Variant<int, double, std::string> bob;
bob.emplace<0>( 7 );
bob.emplace<1>( 3.14 );
bob.emplace<2>( "hello world" );
}
here is a really simple variant interface.
The hard part is turning a runtime index into which of the compile time indexes you want to use. I call that the magic switch problem.
You might also want to implement apply visitor.
...
Or...
template<class T>
struct Derived;
struct Base {
virtual ~Base() {}
template<class T>
friend T* get(Base* base) {
Derived<T>* self = dynamic_cast<T*>(base);
return self?&self.t:nullptr;
}
template<class T>
friend T const* get(Base const* base) {
Derived<T> const* self = dynamic_cast<T const*>(base);
return self?&self.t:nullptr;
}
};
template<class T>
struct Derived:Base {
Derived(T in):t(std::move(in)){}
T t;
};
std::unordered_map<std::string, std::unique_ptr<Base>> map;
map["hello"] = std::unique_ptr<Base>( new Derived<int>(-1) );
map["world"] = std::unique_ptr<Base>( new Derived<double>(3.14) );
int* phello = get<int>(map["hello"]);
if (phello) std::cout << *hello << "\n";
double* pworld = get<double>(map["world"]);
if (pworld) std::cout << *world << "\n";
which is a seriously bargain-basement std::any.

Hashing a template type

Here, I tried to make a map that its vertex can be user-defined class. But when I try to add template type element to the unordered_set it gives error. The code is:
#include <iostream>
#include <unordered_set>
#include <string>
#include <vector>
#include <functional>
template<class T> class Edge;
template<class T> class Vertex{ // Made it a class just for its constructor.
public:
template<class A> Vertex(A vert){
A vertex = vert;
std::unordered_set<Edge<A>> adjlist;
}
};
template<class T> class Edge{ // Made it a class just for its constructor.
public:
template<class A> Edge(Vertex<A> vert1, Vertex<A> vert2, int w){
Vertex<A> *origin = &vert1;
Vertex<A> *target = &vert2;
}
};
template<class T>
class WUG{
private:
std::unordered_set<Vertex<T>> vertices;
std::unordered_set<Edge<T>> edges;
int num_of_edges;
int num_of_vertices;
public:
WUG() {
num_of_edges = 0;
num_of_vertices = 0;
}
void addVertex(T newVert) {
Vertex<T> temp = Vertex<T>(newVert);
vertices.emplace(temp); //Problem is here
}
int main(int argc, char** argv) {
WUG<char> g1 = WUG<char>();
g1.addVertex('A');
g1.addVertex('B');
g1.addVertex('C');
return 0;
}
Error: it opens hashtable_policy.h and gives error at
template <typename _Key, typename _Hash>
struct __is_noexcept_hash : std::integral_constant<bool,
noexcept(declval<const _Hash&>()(declval<const _Key&>()))> //Here
{ };
[Error] no match for call to '(const std::hash<Vertex<char> >) (const Vertex<char>&)'
How do you emplace a template type object to unordered_set? How about pair of 2 template?
I believe you need to provide special hashing and comparison functions to make the hash set (or in my example's case, hash map) work. Here is a minimal example. Tested with C++11.
#include <unordered_map>
#include <iostream>
#include <algorithm>
template<typename T>
struct foo {
typedef T value_type;
foo(T x) : x(x) {}
T x;
};
template<typename T>
struct foo_hasher {
int operator()(const T &val) const {
return std::hash<typename T::value_type>()(val.x);
}
};
template<typename T>
struct foo_equality {
bool operator()(const T &left, const T& right) const {
return left.x == right.x;
}
};
int main() {
typedef std::unordered_map<foo<int>, int, foo_hasher<foo<int>>, foo_equality<foo<int>>> Map;
Map mp;
foo<int> x(5);
mp[x] = 10;
mp[foo<int>(10)] = 22;
std::for_each(mp.begin(), mp.end(), [](const Map::value_type &val) {
std::cout << val.first.x << ", " << val.second << "\n";
});
}
Note that both my hashing and equality function are not at all restrictive - they are wrt T rather than foo, but the principal should be the same.

combining a vector and int in c++11?

Say if I had a vector<string> already defined and filled called test and an int called a. If I wanted to combine these 2 into a single object called combined where i could do combined[0] = test; to initialize/retrieve the object with the vector and combined[1] = a; to initialize/retrieve the object with the int, what would be the best function to do so and how would I do so? I had attempted to do vector<vector<string>, int> but this gave me an error.
Note: I am compiling with -std=c++11 if this matters.
Use a std::tuple<std::vector<std::string>,int>.
#include <tuple>
#include <vector>
#include <string>
int main() {
std::vector<std::string> test;
int a{};
std::tuple<std::vector<std::string>,int> combined;
//To access elements, use `std::get`:
std::get<0>(combined) = test;
std::get<1>(combined) = a;
}
to answer cellsheet's comment: that function already exists, it's called std::make_tuple() (see also comment by fjardon on how to store this).
Btw, why do you need to extend std::vector<std::string> by an int?
If I understand correctly what you're asking, I think you can do this with a std::pair:
std::pair<std::vector<std::string>, int> combined;
combined.first = test; // assign vector
combined.second = a; // assign int
or simply
auto combined = std::make_pair(test,a);
It requires (ugly) type elision:
#include <iostream>
#include <stdexcept>
#include <type_traits>
#include <vector>
class X {
public:
typedef std::vector<std::string> vector_type;
typedef int integer_type;
private:
enum Type {
TypeVector,
TypeInteger
};
template <bool Constant>
class Proxy
{
private:
typedef typename std::conditional<
Constant, const void, void>::type void_t;
public:
typedef typename std::conditional<
Constant, const vector_type, vector_type>::type vector_t;
typedef typename std::conditional<
Constant, const integer_type, integer_type>::type integer_t;
Proxy(vector_t& v)
: m_type(TypeVector), m_data(&v)
{}
Proxy(integer_t& i)
: m_type(TypeInteger), m_data(&i)
{}
operator vector_t& () const {
if(m_type != TypeVector) throw std::runtime_error("Invalid Type");
return *static_cast<vector_t*>(m_data);
}
operator integer_t& () const {
if(m_type != TypeInteger) throw std::runtime_error("Invalid Type");
return *static_cast<integer_t*>(m_data);
}
private:
template <typename T, typename U, bool> struct Assignment
{
static void apply(void_t*, const U&) {}
};
template <typename T, typename U>
struct Assignment<T, U, true>
{
static void apply(void_t* p, const U& value) {
*static_cast<T*>(p) = value;
}
};
template <typename T, typename U>
// Attention: Use a reference - std::is_assignable<int, int>::value> is false;
struct Assign : Assignment<T, U, std::is_assignable<T&, U>::value>
{};
public:
template <typename U>
Proxy&
operator = (const U& value) {
static_assert( ! Constant, "Assignment to Constant");
switch(m_type) {
case TypeVector:
Assign<vector_t, U>::apply(m_data, value);
break;
case TypeInteger:
Assign<integer_t, U>::apply(m_data, value);
break;
default: throw std::out_of_range("Invalid Type");
}
return *this;
}
private:
Type m_type;
void_t* m_data;
};
public:
X() : m_v{"Hello"}, m_i(1) {}
Proxy<true> operator [] (std::size_t i) const {
switch(i) {
case 0: return Proxy<true>(m_v);
case 1: return Proxy<true>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
Proxy<false> operator [] (std::size_t i) {
switch(i) {
case 0: return Proxy<false>(m_v);
case 1: return Proxy<false>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
private:
vector_type m_v;
integer_type m_i;
};
int main() {
// Note: The Proxy has no operator []
// const
{
const X x;
const X::vector_type& v = x[0];
std::cout << v[0] << " " << x[1] << std::endl;
}
// non const
{
X x;
X::vector_type& v = x[0];
v[0] = "World";
x[1] = 2;
std::cout << v[0] << " " << x[1] << std::endl;
}
}
You might consider boost::any, instead.

Convert a std::vector of a boost::variant type

How might I implement the function below to convert from vector of Value to a Container? I wish to assert if not all the members of values are of the same type, i.e. if the vector contains a mix of strings and ints. This is because the function's return value is either a std::vector<int> or a std::vector<std::string>.
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
Container valuesToContainer(const std::vector<Value>& values)
{
return Container();
}
struct converter_visitor : public boost::static_visitor<Container>
{
const std::vector<Value> & _cont;
converter_visitor(const std::vector<Value> &r) : _cont(r) {}
template<class T>
Container operator()(const T &) const {
std::vector<T> ans;
ans.reserve(_cont.size());
for (int i=0;i < _cont.size();++i)
ans.push_back( boost::get<T>(_cont[i]));
return ans;
}
};
Container valuesToContainer(const std::vector<Value> & values) {
//assuming !values.empty()
return boost::apply_visitor( converter_visitor(values),values.front());
}
This will throw a bad_get if not all the elements of values are of the same type.
This could come in handy, maybe:
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values);
The difference with the function requested by the OP is that instead of 'erroring' when not all element types agree, it will return a tuple of vectors ("VectorPack"), and you can simply select which is the one you want.
Demo program:
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <tuple>
#include <vector>
using std::get;
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
namespace detail
{
template <typename T>
struct VectorSplitterMixin {
void operator()(T const& v) { _bucket.push_back(v); }
std::vector<T> _bucket;
};
template <typename... T>
struct VectorSplitter : boost::static_visitor<>, VectorSplitterMixin<T>...
{
typedef VectorPack<T...> product_t;
product_t product() {
return product_t { std::move(static_cast<VectorSplitterMixin<T>*>(this)->_bucket)... };
}
};
}
template <typename T> struct X;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values)
{
auto splitter = detail::VectorSplitter<T...>();
for (auto& val : values)
boost::apply_visitor(splitter, val);
return splitter.product();
}
int main()
{
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
const std::vector<Value> vec { 42, "hello world", 1, -99, "more" };
auto vectorPack = splitVectors<int, std::string>(vec);
for (auto i : get<0>(vectorPack))
std::cout << "int:" << i << ", ";
std::cout << "\n";
for (auto& s : get<1>(vectorPack))
std::cout << "string:" << s << ", ";
std::cout << "\n";
}
Printing:
int:42, int:1, int:-99,
string:hello world, string:more,