I'm a CS student, and the I have a task where I need some help. The task is to create a vectors_predicate_view class that gets a T type as the first template parameter and a predicate as the second template parameter. In its constructor the class should get 2 std::vectors as parameters.
Here is the class:
#pragma once
#include <vector>
template<typename T, typename Predicate>
class vectors_predicate_view
{
private:
Predicate predict;
std::vector<T> originalContents1;
std::vector<T> originalContents2;
std::vector<T> &original1; // reference to original vector1
std::vector<T> &original2; // reference to original vector2
void setElements(std::vector<T> &vector1, std::vector<T> &vector2)
{
//Putting every element from vector1 into originalContents1
for(auto element : vector1)
originalContents1.push_back(element);
vector1.clear(); //Emptying vector1
//Putting every element from vector2 into originalContents2
for(auto element : vector2)
originalContents2.push_back(element);
vector2.clear(); //Emptying vector2
//We loop through originalContents1
//if the element gives back true for the predictatum, we add it to vector1
//else it goes to vector2
for(auto element : originalContents1)
{
if (predict(element))
vector1.push_back(element);
else
vector2.push_back(element);
}
//We loop through originalContents2
//if the element gives back true for the predictatum, we add it to vector1
for(auto element : originalContents2)
if(predict(element))
vector1.push_back(element);
}
public:
vectors_predicate_view(std::vector<T> &vector1, std::vector<T> &vector2) : original1(vector1), original2(vector2)
{
setElements(vector1, vector2);
}
};
The task is to make the second parameter optional, and if it's not given, the class should not do anything with the 2 given vectors inside its constructor.
Just to give an idea, here is how that second template optimally looks like. It's an std::unary_function that looks like this:
struct is_even: std::unary_function<int, bool>
{
bool operator()(int i) const
{
return 0 == i % 2;
}
};
struct is_good_language: std::unary_function<std::string, bool>
{
bool operator()(const std::string& s) const
{
return s == "C++" || s == "C";
}
};
and called like this:
const vectors_predicate_view<int, is_even> va(a, b);
vectors_predicate_view<std::string, is_good_language> vb(x, y);
Any help would be greatly appreciated!
You can define a predicate that always returns true no matter what the argument is:
struct always_true {
template <typename T>
constexpr bool operator()(T&&) const noexcept {
return true;
}
};
Then, set this predicate to be the default argument for the template parameter Predicate:
template <typename T, typename Predicate = always_true>
// ^^^^^^^^^^^^^ default argument
class vectors_predicate_view {
// ...
};
When the user explicitly supplies an argument, the default argument is ignored.
To differentiate the default case from user-supplies predicates, an alternative approach is to put the tag in a detail namespace — which is private to the implementation, by convention — and use specialization to handle the case:
namespace detail {
struct tag {};
}
template <typename T, typename Predicate = detail::tag>
// ^^^^^ default argument
class vectors_predicate_view {
// normal case
};
template <typename T>
class vectors_predicate_view<T, detail::tag> {
// default case
};
When the user does not provide the second template argument, the specialization is used. This may cause some code duplication, but it gives you full control over what to do in the default case.
Aside: since C++11, there is no need to derive from unary_function, etc. — see Why have unary_function, binary_function been removed from C++11?.
Related
If I have a class containing only std::vector of any type as data member and I would like to make a generic function allowing me to retrieve elements by index in any vector.
What can I do to create such a function. I tried to do it using pointers to my getters and it worked but I don't know if it is really a good solution.
Is there an example of such class
class S
{
private:
std::vector<int> someIntegers;
std::vector<double> someDoubles;
std::vector<double> someDoubles2;
std::vector<int> someIntergers2;
std::vector<B> someBs;
public:
const std::vector<int>& getSomeIntegers1() const { return someIntergers; }
// and so on ...
}
My solution is to do that:
template<typename T>
std::optional<T> getByIndex(const S& s, const std::vector<T>& (S::*getCnt)() const , size_t index = 0)
{
if (const auto& cnt = (s.*getCnt)();
index >= 0 && index < cnt.size())
return cnt.at(index);
return {};
}
I'm not sure if it's a great solution due to the lack of readability.
If you want to have a generic access that routes to individual members based on the template parameter, you must define the mapping manually. However, using the template argument as selector will not support cases with multiple member vectors of the same type, for example the someDoubles and someDoubles2.
Here is a sample code to retrieve the correct vector
template <class T>
std::vector<T>& getContainer();
template <>
std::vector<int>& getContainer() {
return someIntegers;
}
template <>
std::vector<double>& getContainer() {
return someDoubles;
}
// Do so for every type you want to support
I'm pretty new in C++. I have wrote a function template to sum all elements in a vector like this:
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
T init = T{};
return accumulate(sequence.begin(), sequence.end(), init);
}
All work well until the default constructor is not declare, but declare constructor from, for example, 2 arguments.
Like this:
class A {
private:
int a;
int b;
public:
// A() = default;
A(int aa, int bb) : a(aa),b(bb){};
A operator+(const A &right) const {
return {a + right.a, b + right.b};
}
bool operator==(const A &right) const {
return (a == right.a && b == right.b);
}
};
vector<A> bc = {{3,5},{5,5}};
A res = Adder::sumator(works);
A result = {8,10};
assert(result,res);
Now I get an error like : error: no matching constructor for initialization of 'A'
T init = T{};
How can I avoid this situation, not using https://en.cppreference.com/w/cpp/types/is_default_constructible
UPD: I have many classes, some of them with default constructor, some without but with constructor for 2 arg, some for 3, e.t.c. And I want to accumulate every situation well
Possible solutions that I can think of.
Let users rely on std::accumulate by providing an initial vlaue.
Provide an overload of sumator with an initial value. Users can call the overload with an initial value if they have a type that does not have default constructor.
Insist that the type for which the function is invoked have a default consructor.
template<typename T>
inline T sumator(const std::vector<T> &sequence, T init) {
return accumulate(sequence.begin(), sequence.end(), init);
}
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
return accumulate(sequence.begin(), sequence.end(), {});
}
You can add another parameter with default argument.
template<typename T>
inline T sumator(const std::vector<T> &sequence, const T& init = T{}) {
return accumulate(sequence.begin(), sequence.end(), init);
}
For types could be default-constructed you can still
sumator(some_vector);
And specify the default value when T can't be default-constructed. e.g.
sumator(some_vector, A{0, 0});
You can split it in two overloads and add a static_assert to provide a nice compilation error message if someone tries to use it the wrong way.
One overload would be valid only if the type is default constructible and one overload would be valid for types that is not as well as for those that are:
#include <type_traits>
#include <vector>
template<typename T>
T sumator(const std::vector<T>& sequence) {
static_assert(std::is_default_constructible_v<T>);
return std::accumulate(sequence.begin(), sequence.end(), T{});
}
template<typename T>
T sumator(const std::vector<T>& sequence, const T& init) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}
Another option is to add a default argument that can be used for types that are default constructible - and you could also make it more generic to make it work with not only vectors but with lists etc.
template<template<class, class...> class C, class T, class... Ts>
T sumator(const C<T, Ts...>& sequence, const T& init = T{}) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}
Suppose I want to write a recursive template function that compares an individual value to every single element in an n-dimensional vector, returning true if there is at least one match and false if there are none.
I wrote some code to do this, although it's probably far from optimal:
template <typename T, typename Checker>
void check_for_each(const T& v, const Checker condition)
{
condition(v);
}
template <typename T, typename Checker>
void check_for_each(const std::vector<T>& v, const Checker condition)
{
for(unsigned int i = 0; i < v.size(); i++)
{
check_for_each(v[i], condition);
}
}
template <typename T, typename U>
bool is_equal_any(const T& VALUE, const std::vector<typename U> VECTOR)
{
bool is_equal = false;
check_for_each(VECTOR, [&is_equal, &VALUE](const T& val)
{
if(!is_equal && VALUE == val)
{
is_equal = true;
}
});
return is_equal;
}
While this seems to work, I've encountered an unusual issue and I can't quite understand it. For example, the following code works:
enum PIECE_NAME {EMPTY, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING};
std::vector<std::vector<int>> board {{ROOK, BISHOP}, {KNIGHT, QUEEN}};
std::cout << is_equal_any(2, board); // outputs 1 (there is a rook on the board)
Yet the following, slight change does not:
std::cout << is_equal_any(ROOK, board); // compile error C2664
Apparently my function cannot figure out how to convert the enum value to an integer. Of course, I can just use static_cast<int>(ROOK), and the code compiles and runs as expected, but that's obviously not ideal. Furthermore, I know that I can change my board's declaration to std::vector<std::vector<PIECE_NAME>> board, (which also runs as expected) but I'd prefer to leave it at int. So is it possible to rewrite these recursive template functions so that is_equal_any can take enum values directly? I'm still very new to C++, so I would really appreciate as much detail in your answer as possible. Thank you.
The problem arises from the type T here:
check_for_each(VECTOR, [&is_equal, &VALUE](const T& val)
^
By calling
is_equal_any(ROOK, board)
T is a PIECE_NAME, but what you are finally passing as parameter to this lambda are the elements of your vector of type int. But an int can't be implicitly converted to an enum.
You can't either use directly U as it could be a std::vector<int> or std::vector< std::vector<int> > or...
If you were using C++14, you could use a generic lambda with auto:
check_for_each(VECTOR, [&is_equal, &VALUE](const auto& val)
But as you tagged your question C++11, you can use a trait:
template <typename T>
struct leaf_type {
using type = T;
};
template <typename T>
struct leaf_type<std::vector<T>> {
using type = typename leaf_type<T>::type;
};
template <typename T>
using leaf_type_t = typename leaf_type<T>::type;
usage:
check_for_each(VECTOR, [&is_equal, &VALUE](const leaf_type_t<U> & val)
DEMO
Btw you should avoid nested std::vectors and linearize it into a single one like:
std::vector<int> board {ROOK, BISHOP, KNIGHT, QUEEN};
Then you can easily use std::find.
This is kind of an XY problem, as there are better approaches:
Use a scoped enum
don't mix integers and enums
delegate your work to std::any_of
For example:
namespace multi_dim{
template< class InputIt, class UnaryPredicate >
bool any_of(InputIt first, InputIt last, UnaryPredicate p)
{
using std::any_of;
for(;first != last; ++first)
{
bool next = any_of(first->cbegin(), first->cend(), p);
if (next)
return true;
}
return false;
}
}
Demo
A test:
std::vector<std::vector<PIECE>> board {{PIECE::ROOK, PIECE::BISHOP}, {PIECE::KNIGHT, PIECE::QUEEN}};
std::cout << std::boolalpha << multi_dim::any_of(board.cbegin(), board.cend(), [](PIECE p){return p == PIECE::ROOK;}) << std::endl;
std::cout << std::boolalpha << multi_dim::any_of(board.cbegin(), board.cend(), [](PIECE p){return p == PIECE::EMPTY;}) << std::endl;
Output:
true
false
Wild guess: Try a difference template parameter for VALUE and for the element type of VECTOR.
I don't use MSVC so I'm not sure exactly what error you're getting.
... regardless of all that, I just have to repeat my comment: Please don't write this kind of code.
Although the solution using std::any_of is the best one, I give my answer that show somewhat less drastic improvement to original code.
template <typename T, typename Checker>
bool check_for_each(const T& v, const Checker condition)
{
return condition(v);
}
template <typename T, typename Checker>
bool check_for_each(const std::vector<T>& v, const Checker condition)
{
return std::find_if(begin(v), end(v), [condition](const T &t) { return check_for_each(t, condition); }) != v.end();
}
template <typename T, typename U>
bool is_equal_any(const T& value, const U &container)
{
return check_for_each(container, [&value](const T& val){ return value == val; });
}
enum class PIECE_NAME { EMPTY, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING };
void test()
{
std::vector<std::vector<PIECE_NAME>> board
{
{ PIECE_NAME::ROOK, PIECE_NAME::BISHOP },
{ PIECE_NAME::KNIGHT, PIECE_NAME::QUEEN }
};
std::cout << is_equal_any(PIECE_NAME::ROOK, board);
}
This solution is still hard-coded for nested vectors but the code has been simplified a bit and also optimized as it will stop searching once an item is found.
As already suggested in other comments, you should really use enum (or better yet enum class). It does not make much sense to store integers in the vector as you loose type information.
I have a class Vector which represents a mathematical vector of a given template class. I want to be able to save the vectors in two different ways:
template <class T>
class Vector
{
private:
T* elements;
};
and
template <class T, unsigned int D>
class Vector
{
private:
T elements[D];
};
In the first example I allocate and free the array with new and delete in constructor and destructor.
Now since I don't want to write all the methods twice for both classes, and since it wouldn't even compile this way because I have two classes with the same name but different template arguments, I would like to combine both classes into one class like so:
template <class T, int D = -1>
class Vector
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T elements[D];
};
template <class T>
class Vector<T, -1>
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T* elements;
};
So the second part is just a partial template specialization of the first one. If no dimensions are given the dynamically allocated option should be used (default argument for D). As an example I added a function to calculate the sum of two vectors.
Now my problem is that I have to give two implementations for what is logically just one function. Whenever I access the elements array it's exactly the same syntax in the dynamic and in the static Vector class. Can I somehow combine both implementations into just one implementation of the add function (and likewise of all similar functions)?
If I cannot solve the problem this way, do you have other ideas of how to create the Vector class with both dynamic and static memory allocation?
I'd go for a policy-based design, similar to the way how std::vector handles allocation.
In your case it means:
Define a class which stores the vector elements but only provides a minimal interface. (Policy)
Define your vector interface independent of the way the elements are stored in the policy. It accesses the elements in a way independent of that implementation. The policy class should be added as a template type parameter (which can have a default value), so the user of your vector class can choose which policy to use. Inherit from the policy class or add a member of its type (privately if you don't want to expose the policy interface in the public interface).
Example (here with aggregation instead of inheritance):
// The policy default implementation:
template <class T, int D>
class VectorStorage
{
T elements[D];
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
class VectorStorage<T, -1>
{
T* elements; // (for allocation, see below)
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
// The vector implementation, independent of the storage,
// but defaulting to the one above:
template <class T, int D = -1, class Storage = VectorStorage<T,D>>
class Vector
{
Storage storage;
public:
Vector<T, D> add(const Vector<T, D>& add) const {
// Access your elements using "storage[x]"
}
};
Note that you need a suitable constructor for your policy class (as in the case of the dynamic storage type, you need the size during construction). Provide a unique constructor interface to all of your specializations, not only for the one which need it; and call the constructor in the vector's constructor appropriately:
// within class VectorStorage<T,-1>:
VectorStorage(int size) : elements(new T[size]) {}
~VectorStorage() { delete[] elements; }
// within class VectorStorage<T,D>:
VectorStorage(int /* ignored */) {}
// within class Vector:
Vector(int size) : storage(size) {}
Alternatively, to support client code like Vector<int,5> myVector; (i.e. default constructor on the static size version), provide a default constructor which is only allowed to be called for the static size version:
Vector() : storage(D) {
static_assert(D != -1, "The default constructor is only allowed for the static-sized version of Vector.");
}
Now a user can even use Vector with std::vector as the storage back-end: Vector<int, -1, std::vector<int>> or Vector<int, 5, std::vector<int>>. Or even Vector<int, 5, std::array<int,5>>.
I would do something like the following, i.e specialize only the data part:
template <class T, int D = -1>
class VectorData
{
public:
int size() const { return D; }
protected:
T elements[D];
};
template <class T>
class VectorData<T, -1>
{
public:
explicit VectorData(int size) : elements(size) {}
int size() const { return elements.size(); }
protected:
std::vector<T> elements;
};
template <class T, int D = -1>
class Vector : protected VectorData<T, D>
{
public:
using VectorData<T, D>::VectorData;
Vector add(const Vector& add) const
{
Vector res(*this);
for (int i = 0; i != this->size(); ++i) {
res.elements[i] += add.elements[i];
}
return res;
}
};
Suppose I have a bunch of vectors:
vector<int> v1;
vector<double> v2;
vector<int> v3;
all of the same length. Now, for every index i, I would like to be able to treat (v1[i], v2[i], v3[i]) as a tuple, and maybe pass it around. In fact, I want to have a a vector-of-tuples rather than a tuple-of-vectors, using which I can do the above. (In C terms, I might say an array-of-structs rather than a struct-of-arrays). I do not want to effect any data reordering (think: really long vectors), i.e. the new vector is backed by the individual vectors I pass in. Let's .
Now, I want the class I write (call it ToVBackedVoT for lack of a better name) to support any arbitrary choice of vectors to back it (not just 3, not int, double and int, not every just scalars). I want the vector-of-tuples to be mutable, and for no copies to be made on construction/assignments.
If I understand correctly, variadic templates and the new std::tuple type in C++11 are the means for doing this (assuming I don't want untyped void* arrays and such). However, I only barely know them and have never worked with them. Can you help me sketch out how such a class will look like? Or how, given
template <typename ... Ts>
I can express something like "the list of template arguments being the replacement of each typename in the original template arguments with a vector of elements of this type"?
Note: I think I might also want to later be able to adjoin additional vectors to the backing vectors, making an instance of ToVBackedVoT<int, double, int> into, say, an instance of ToVBackedVoT<int, double, int, unsigned int>. So, bear that in mind when answering. This is not critically important though.
One idea is to keep the storage in the "struct of array" style in form of vectors for good performance if only a subset of the fields are used for a particular task. Then, for each kind of task requiring a different set of fields, you can write a lightweight wrapper around some of those vectors, giving you a nice random access iterator interface similar to what std::vector supports.
Concerning the syntax of variadic templates, this is how a wrapper class (without any iterators yet) could look like:
template<class ...Ts> // Element types
class WrapMultiVector
{
// references to vectors in a TUPLE
std::tuple<std::vector<Ts>&...> m_vectors;
public:
// references to vectors in multiple arguments
WrapMultiVector(std::vector<Ts> & ...vectors)
: m_vectors(vectors...) // construct tuple from multiple args.
{}
};
To construct such a templated class, it's often preferred to have a template type deducting helper function available (similar to those make_{pair|tuple|...} functions in std):
template<class ...Ts> // Element types
WrapMultiVector<Ts...> makeWrapper(std::vector<Ts> & ...vectors) {
return WrapMultiVector<Ts...>(vectors...);
}
You already see different types of "unpacking" the type list.
Adding iterators suitable to your application (you requested in particular random access iterators) is not so easy. A start could be forward only iterators, which you might extend to random access iterators.
The following iterator class is capable of being constructed using a tuple of element iterators, being incremented and being dereferenced to obtain a tuple of element references (important for read-write access).
class iterator {
std::tuple<typename std::vector<Ts>::iterator...> m_elemIterators;
public:
iterator(std::tuple<typename std::vector<Ts>::iterator...> elemIterators)
: m_elemIterators(elemIterators)
{}
bool operator==(const iterator &o) const {
return std::get<0>(m_elemIterators) == std::get<0>(o.m_elemIterators);
}
bool operator!=(const iterator &o) const {
return std::get<0>(m_elemIterators) != std::get<0>(o.m_elemIterators);
}
iterator& operator ++() {
tupleIncrement(m_elemIterators);
return *this;
}
iterator operator ++(int) {
iterator old = *this;
tupleIncrement(m_elemIterators);
return old;
}
std::tuple<Ts&...> operator*() {
return getElements(IndexList());
}
private:
template<size_t ...Is>
std::tuple<Ts&...> getElements(index_list<Is...>) {
return std::tie(*std::get<Is>(m_elemIterators)...);
}
};
For demonstration purposes, two different patterns are in this code which "iterate" over a tuple in order to apply some operation or construct a new tuple with some epxression to be called per element. I used both in order to demonstrate alternatives; you can also use the second method only.
tupleIncrement: You can use a helper function which uses meta programming to index a single entry and advance the index by one, then calling a recursive function, until the index is at the end of the tuple (then there is a special case implementation which is triggered using SFINAE). The function is defined outside of the class and not above; here is its code:
template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I == sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{ }
template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I < sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{
++std::get<I>(tup);
tupleIncrement<I + 1, Ts...>(tup);
}
This method can't be used to assign a tuple of references in the case of operator* because such a tuple has to be initialized with references immediately, which is not possible with this method. So we need something else for operator*:
getElements: This version uses an index list (https://stackoverflow.com/a/15036110/592323) which gets expanded too and then you can use std::get with the index list to expand full expressions. The IndexList when calling the function instantiates an appropriate index list which is only required for template type deduction in order to get those Is.... The type can be defined in the wrapper class:
// list of indices
typedef decltype(index_range<0, sizeof...(Ts)>()) IndexList;
More complete code with a little example can be found here: http://ideone.com/O3CPTq
Open problems are:
If the vectors have different sizes, the code fails. Better would be to check all "end" iterators for equality; if one iterator is "at end", we're also "at end"; but this would require some logic more than operator== and operator!= unless it's ok to "fake" it in; meaning that operator!= could return false as soon as any operator is unequal.
The solution is not const-correct, e.g. there is no const_iterator.
Appending, inserting etc. is not possible. The wrapper class could add some insert or and / or push_back function in order to make it work similar to std::vector. If your goal is that it's syntactically compatible to a vector of tuples, reimplement all those relevant functions from std::vector.
Not enough tests ;)
An alternative to all the variadic template juggling is to use the boost::zip_iterator for this purpose. For example (untested):
std::vector<int> ia;
std::vector<double> d;
std::vector<int> ib;
std::for_each(
boost::make_zip_iterator(
boost::make_tuple(ia.begin(), d.begin(), ib.begin())
),
boost::make_zip_iterator(
boost::make_tuple(ia.end(), d.end(), ib.end())
),
handle_each()
);
Where your handler, looks like:
struct handle_each :
public std::unary_function<const boost::tuple<const int&, const double&, const int&>&, void>
{
void operator()(const boost::tuple<const int&, const double&, const int&>& t) const
{
// Now you have a tuple of the three values across the vector...
}
};
As you can see, it's pretty trivial to expand this to support an arbitrary set of vectors..
From asker's clarification on how this would be used (code that takes a tuple), I'm going to propose this instead.
//give the i'th element of each vector
template<typename... Ts>
inline tuple<Ts&...> ith(size_t i, vector<Ts>&... vs){
return std::tie(vs[i]...);
}
There's a proposal to allow parameter packs to be saved as members of classes (N3728). Using that, here's some untested and untestable code.
template<typename... Types>
class View{
private:
vector<Types>&... inner;
public:
typedef tuple<Types&...> reference;
View(vector<Types>&... t): inner(t...) {}
//return smallest size
size_t size() const{
//not sure if ... works with initializer lists
return min({inner.size()...});
}
reference operator[](size_t i){
return std::tie(inner[i]...);
}
};
And iteration:
public:
iterator begin(){
return iterator(inner.begin()...);
}
iterator end(){
return iterator(inner.end()...);
}
//for .begin() and .end(), so that ranged-based for can be used
class iterator{
vector<Types>::iterator... ps;
iterator(vector<Types>::iterator... its):ps(its){}
friend View;
public:
//pre:
iterator operator++(){
//not sure if this is allowed.
++ps...;
//use this if not:
// template<typename...Types> void dummy(Types... args){} //global
// dummy(++ps...);
return *this;
}
iterator& operator--();
//post:
iterator operator++(int);
iterator operator--(int);
//dereference:
reference operator*()const{
return std::tie(*ps...);
}
//random access:
iterator operator+(size_t i) const;
iterator operator-(size_t i) const;
//need to be able to check end
bool operator==(iterator other) const{
return std::make_tuple(ps...) == std::make_tuple(other.ps...);
}
bool operator!=(iterator other) const{
return std::make_tuple(ps...) != std::make_tuple(other.ps...);
}
};
You may use something like:
#if 1 // Not available in C++11, so write our own
// class used to be able to use std::get<Is>(tuple)...
template<int... Is>
struct index_sequence { };
// generator of index_sequence<Is>
template<int N, int... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> { };
#endif
// The 'converting' class
// Note that it doesn't check that vector size are equal...
template<typename ...Ts>
class ToVBackedVoT
{
public:
explicit ToVBackedVoT(std::vector<Ts>&... vectors) : data(vectors...) {}
std::tuple<const Ts&...> operator [] (unsigned int index) const
{
return at(index, make_index_sequence<sizeof...(Ts)>());
}
std::tuple<Ts&...> operator [] (unsigned int index)
{
return at(index, make_index_sequence<sizeof...(Ts)>());
}
private:
template <int... Is>
std::tuple<const Ts&...> at(unsigned int index, index_sequence<Is...>) const
{
return std::tie(std::get<Is>(data)[index]...);
}
template <int... Is>
std::tuple<Ts&...> at(unsigned int index, index_sequence<Is...>)
{
return std::tie(std::get<Is>(data)[index]...);
}
private:
std::tuple<std::vector<Ts>&...> data;
};
And to iterate, create an 'IndexIterator' like the one in https://stackoverflow.com/a/20272955/2684539
To adjoin additional vectors, you have to create an other ToVBackedVoT as std::tuple_cat does for std::tuple
Conversion to a std::tuple of vectors (vector::iterators):
#include <iostream>
#include <vector>
// identity
// ========
struct identity
{
template <typename T>
struct apply {
typedef T type;
};
};
// concat_operation
// ================
template <typename Operator, typename ...> struct concat_operation;
template <
typename Operator,
typename ...Types,
typename T>
struct concat_operation<Operator, std::tuple<Types...>, T>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef std::tuple<Types..., concat_type> type;
};
template <
typename Operator,
typename ...Types,
typename T,
typename ...U>
struct concat_operation<Operator, std::tuple<Types...>, T, U...>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef typename concat_operation<
Operator,
std::tuple<Types..., concat_type>,
U...>
::type type;
};
template <
typename Operator,
typename T,
typename ...U>
struct concat_operation<Operator, T, U...>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef typename concat_operation<
Operator,
std::tuple<concat_type>,
U...>
::type type;
};
// ToVectors (ToVBackedVoT)
// =========
template <typename ...T>
struct ToVectors
{
private:
struct to_vector {
template <typename V>
struct apply {
typedef typename std::vector<V> type;
};
};
public:
typedef typename concat_operation<to_vector, T...>::type type;
};
// ToIterators
// ===========
template <typename ...T>
struct ToIterators;
template <typename ...T>
struct ToIterators<std::tuple<T...>>
{
private:
struct to_iterator {
template <typename V>
struct apply {
typedef typename V::iterator type;
};
};
public:
typedef typename concat_operation<to_iterator, T...>::type type;
};
int main() {
typedef ToVectors<int, double, float>::type Vectors;
typedef ToVectors<Vectors, int, char, bool>::type MoreVectors;
typedef ToIterators<Vectors>::type Iterators;
// LOG_TYPE(Vectors);
// std::tuple<
// std::vector<int, std::allocator<int> >,
// std::vector<double, std::allocator<double> >,
// std::vector<float, std::allocator<float> > >
// LOG_TYPE(Iterators);
// std::tuple<
// __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >,
// __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >,
// __gnu_cxx::__normal_iterator<float*, std::vector<float, std::allocator<float> > > >
}
As an alternative similar to boost::zip_iterator I wrote a zip function with a very simple interface:
vector<int> v1;
vector<double> v2;
vector<int> v3;
auto vec_of_tuples = zip(v1, v2, v3);
For example, iterate over these tuples:
for (auto tuple : zip(v1, v2, v3)) {
int x1; double x2; int x3;
std::tie(x1, x2, x3) = tuple;
//...
}
Here, zip() takes any number of ranges of any type. It returns an adaptor which can be seen as a lazily evaluated range over a tuple of elements originating from the wrapped ranges.
The adaptor is part of my Haskell-style functional library "fn" and implemented using variadic templates.
Currently it doesn't support modification of the original ranges' values via the adaptor because of the design of the library (it's intended to be used with non-mutable ranges like in functional programming).
A brief explanation on how this is done is: zip(...) returns an adaptor object which implements begin() and end(), returning an iterator object. The iterator holds a tuple of iterators to the wrapped ranges. Incrementing the iterator increments all wrapped iterators (which is implemented using an index list and unpacking an incrementing expression into a series of expressions: ++std::get<I>(iterators)...). Dereferencing the iterator will decrement all wrapped iterators and pass it to std::make_tuple (which is also implemented as unpacking the expression *std::get<I>(iterators)...).
P.S. Its implementation is based on a lot of ideas coming from answers to this question.