Adding element to back of STL container - c++

I'm looking for a general way of adding an element to the back of an STL container. I would like the code to support as many types of STL container as possible. The following piece of code demonstrates my problem:
#include <vector>
#include <string>
using namespace std;
template<typename T>
class S {
T built;
typename T::iterator built_it;
public:
S() : built{}, built_it{built.end()} {}
void add_to(typename T::value_type e) {
built.emplace(built_it, e);
++built_it;
}
const T& get() {
return built;
}
};
int main()
{
S<std::vector<int>> e;
S<std::string> f;
e.add_to(3); // works
f.add_to('c'); // doesn't
}
The problem here is subtle. This code works great for vectors, because std::vector implements the emplace function. But std::string does not! Is there a more general way to perform the same operation?

The most generic way (not necessarily the most efficient way) is:
c.insert( c.end(), value );
where, of course, value needs to be suitable for the container c (you may use decltype(c)::value_type). In case of an associative container, e.g. map, it is a std::pair.
This works for all standard containers except for std::forward_list. For some containers the element is then added at the end, for some the c.end() is just a hint that might be ignored.
As a follow up to the comments, here's the advanced stuff ;)
When you want to insert a known number of elements into a given container c (of type C) and you want to be at least somewhat efficient, you should detect wether the container type supports reserve() and call it before inserting elements.
The following method detects reserve() correctly (the link explains how):
template< typename C, typename = void >
struct has_reserve
: std::false_type
{};
template< typename C >
struct has_reserve< C, std::enable_if_t<
std::is_same<
decltype( std::declval<C>().reserve( std::declval<typename C::size_type>() ) ),
void
>::value
> >
: std::true_type
{};
Now you can use it with std::enable_if_t to optionally reserve space. An example could look like this:
template< typename C >
std::enable_if_t< !has_reserve< C >::value >
optional_reserve( C&, std::size_t ) {}
template< typename C >
std::enable_if_t< has_reserve< C >::value >
optional_reserve( C& c, std::size_t n )
{
c.reserve( c.size() + n );
}
template< typename C, typename T, std::size_t N >
void add_array( C& c, const std::array< T, N >& a )
{
optional_reserve( c, N );
for( const auto& e : a ) {
c.insert( c.end(), typename C::value_type( e ) ); // see remark below
}
}
add_array can now be called with all standard containers (except std::forward_list) and it will call reserve() for std::vector and the unordered associative containers.
As the above does not need explicit specialization or overloading for specific container types, it also works for non-standard containers as long as their interfaces are designed reasonably similar to the standard containers' interfaces. (In fact I had several such "home-made" containers in the past and the above Just-Works™)
A remark about the conversion in the above code: The reason for converting the Ts to C::value_type is just to show that this would be the correct place if it is needed. In the above example it might look superfluous, but in my real-world code I call a special conversion traits class to convert the es (which are encoded strings) into the correct value type for any container.

Most often, people use traits.
Many boost libraries have solved this same problem, so you might be able to reuse existing traits.
A simple demonstration: Live on Coliru
#include <vector>
#include <set>
#include <string>
namespace traits
{
template <typename Container, typename Enable = void>
struct add_at_end;
template <typename... TAs>
struct add_at_end<std::vector<TAs...> >
{
using Container = std::vector<TAs...>;
template <typename... CtorArgs>
static void apply(Container& container, CtorArgs&&... args) {
container.emplace_back(std::forward<CtorArgs>(args)...);
}
};
template <typename... TAs>
struct add_at_end<std::set<TAs...> >
{
using Container = std::set<TAs...>;
template <typename... CtorArgs>
static void apply(Container& container, CtorArgs&&... args) {
container.insert(container.end(), { std::forward<CtorArgs>(args)...});
}
};
template <typename... TAs>
struct add_at_end<std::basic_string<TAs...> >
{
using Container = std::basic_string<TAs...>;
template <typename... CtorArgs>
static void apply(Container& container, CtorArgs&&... args) {
container.insert(container.end(), { std::forward<CtorArgs>(args)...});
}
};
}
template <typename Container, typename... CtorArgs>
void add_to(Container& container, CtorArgs&&... args) {
traits::add_at_end<Container>::apply(container, std::forward<CtorArgs>(args)...);
}
int main()
{
using X = std::pair<int, std::string>;
std::vector<X> v;
std::set<X> s;
std::wstring wstr;
std::string str;
add_to(v, 12, "hello");
add_to(s, 42, "world");
add_to(wstr, L'!');
add_to(str, '?');
}
Basically, what you do, is have a free-standing utility function add_to that uses a trait class traits::add_at_end that can be specialized (in this case for any vector<...>, set<...>, or basic_string<...> template instances.
In practice, you would share the implementation for similar containers (e.g. deque and vector) by inheriting the common implementation.

push_back is supported by std::string, std::vector, and std::list. With this, your class template is simply:
template<typename T>
class S {
T built;
public:
S() : built{} {}
void add_to(typename T::value_type e) {
built.push_back(e);
}
const T& get() {
return built;
}
};

Related

Combining n vectors into one vector of n-tuples

I'm thinking about a function with signature
template<typename ...Ts>
std::vector<std::tuple<Ts...>> join_vectors(std::vector<Ts>&&...) {
//...
};
but probably a more general one accepting any iterable instead of just std::vector would be good. Probably it would have a signature like this?
template<template<typename> typename C, typename ...Ts>
C<std::tuple<Ts...>> join_vectors(C<Ts>&&...) {
// ...
};
However, I'm not at this level yet in C++ (despite doing the same in Haskell would be relatively easy), hence I seek for help.
Unfortunately, Range-v3's zip is not at my disposal in this case. I'm tagging it because I think those interested in it are in a better position to help me.
For any indexable containers with size something like this is possible:
#include <tuple>
#include <vector>
#include <algorithm>
// Copy from lvalue containers, move from rvalue containers.
template<typename ...Cs>
auto zip(Cs... vecs) {
std::vector<std::tuple<typename std::decay_t<Cs>::value_type...>> vec;
auto len = std::min({vecs.size()...});
vec.reserve(len);
for(std::size_t i=0;i<len;++i){
vec.emplace_back(std::move(vecs[i])...);
}
return vec;
};
//Return vector of tuples with & for non-const vecs and const& if const.
template<typename ...Cs>
auto zip_view(Cs&... vecs) {
std::vector<std::tuple<decltype(vecs[0])...>> vec;
auto len = std::min({vecs.size()...});
vec.reserve(len);
for(std::size_t i=0;i<len;++i){
vec.emplace_back(vecs[i]...);
}
return vec;
};
If the containers have properly implemented move constructors, this solution will copy the containers passed as lvalues and move from rvalue ones.
Very slight downside is that lvalue containers are copied whole first instead of only the individual elements.
Example [Godbolt]
#include <iostream>
#include <memory>
template<typename T, typename...Args>
void print_tuple(const T& first, const Args&... args){
std::cout<<'('<<first;
((std::cout<<','<< args),...);
std::cout<<')';
}
template<typename T>
struct helper{
using fnc_t = void;
};
template<typename...Args>
struct helper<std::tuple<Args...>>{
using fnc_t = void(*)(const Args&... args);
};
template<typename...Args>
struct helper<std::tuple<Args&...>>{
using fnc_t = void(*)(const Args&... args);
};
template<typename T>
using fnc_t2 = typename helper<T>::fnc_t;
template<typename T>
void template_apply(fnc_t2<T> f, const T& tuple){
std::apply(f, tuple);
}
template<typename T>
void print_vec(const std::vector<T>& vec){
for(const auto&e:vec){
template_apply(print_tuple,e);
std::cout<<'\n';
}
}
struct MoveOnlyFoo{
MoveOnlyFoo(int i):m_i(i){}
int m_i;
std::unique_ptr<int> ptr = nullptr;
};
std::ostream& operator<<(std::ostream& o, const MoveOnlyFoo& foo){
return o<<foo.m_i;
}
int main(){
std::vector v1{1,2,3,4,5,6};
std::vector v2{'a','b','c','d','e'};
std::vector v3{1.5,3.5,7.5};
std::vector<MoveOnlyFoo> vmove;
vmove.emplace_back(45);
vmove.emplace_back(46);
vmove.emplace_back(47);
const std::vector v4{-1,-2,-3,-4,-5};
//Move rvalues, copy lvalue.
print_vec(zip(v1,v2,v3, v4, std::move(vmove)));
// This won't work since the elements from the last vector cannot be copied.
//print_vec(zip(v1,v2,v3, v4, vmove));
std::cout<<"View:\n";
//View, provides const& for const inputs, & for non-const
print_vec(zip_view(v1,v2,v3,v4));
std::cout<<"Modify and print:\n";
for(auto& [x,y]: zip_view(v1,v2)){
++x,++y;
}
// Note the view can work with const containers, returns tuple of `const T&`.
print_vec(zip_view(std::as_const(v1),std::as_const(v2)));
}
Output
(1,a,1.5,-1,45)
(2,b,3.5,-2,46)
(3,c,7.5,-3,47)
View:
(1,a,1.5,-1)
(2,b,3.5,-2)
(3,c,7.5,-3)
Modify and print:
(2,b)
(3,c)
(4,d)
(5,e)
(6,f)
Please disregard the readability of the printing code ;)
I modeled it after python zip functionality. Note your initial proposal copies the vectors, so the output is a vector with the values moved from the parameters.
Returning an iterable Cs is harder because you would have to specify how to insert elements into it, iterators cannot do it on their own.
Getting it work with iterators (but returning still a vector) is a chore, but in theory also possible.

What is the C++ equivalent of Python's "in" operator?

What is the C++ way of checking if an element is contained in an array/list, similar to what the in operator does in Python?
if x in arr:
print "found"
else
print "not found"
How does the time complexity of the C++ equivalent compare to Python's in operator?
The time complexity of Python's in operator varies depending on the data structure it is actually called with. When you use it with a list, complexity is linear (as one would expect from an unsorted array without an index). When you use it to look up set membership or presence of a dictionary key complexity is constant on average (as one would expect from a hash table based implementation):
https://wiki.python.org/moin/TimeComplexity
In C++ you can use std::find to determine whether or not an item is contained in a std::vector. Complexity is said to be linear (as one would expect from an unsorted array without an index). If you make sure the vector is sorted, you can also use std::binary_search to achieve the same in logarithmic time.
http://en.cppreference.com/w/cpp/algorithm/find
Check if element is in the list (contains)
Check if element found in array c++
http://en.cppreference.com/w/cpp/algorithm/binary_search
The associative containers provided by the standard library (std::set, std::unordered_set, std::map, ...) provide the member functions find() and count() and contains() (C++20) for this. These will perform better than linear search, i.e., logarithmic or constant time depending on whether you have picked the ordered or the unordered alternative. Which one of these functions to prefer largely depends on what you want to achieve with that info afterwards, but also a bit on personal preference. (Lookup the documentation for details and examples.)
How to check that an element is in a std::set?
How to check if std::map contains a key without doing insert?
https://en.wikipedia.org/wiki/Associative_containers
http://en.cppreference.com/w/cpp/container
If you want to, you can use some template magic to write a wrapper function that picks the correct method for the container at hand, e.g., as presented in this answer.
You can approach this in two ways:
You can use std::find from <algorithm>:
auto it = std::find(container.begin(), container.end(), value);
if (it != container.end())
return it;
or you can iterate through every element in your containers with for ranged loops:
for(const auto& it : container)
{
if(it == value)
return it;
}
Python does different things for in depending on what kind of container it is. In C++, you'd want the same mechanism. Rule of thumb for the standard containers is that if they provide a find(), it's going to be a better algorithm than std::find() (e.g. find() for std::unordered_map is O(1), but std::find() is always O(N)).
So we can write something to do that check ourselves. The most concise would be to take advantage of C++17's if constexpr and use something like Yakk's can_apply:
template <class C, class K>
using find_t = decltype(std::declval<C const&>().find(std::declval<K const&>()));
template <class Container, class Key>
bool in(Container const& c, Key const& key) {
if constexpr (can_apply<find_t, Container, Key>{}) {
// the specialized case
return c.find(key) != c.end();
} else {
// the general case
using std::begin; using std::end;
return std::find(begin(c), end(c), key) != end(c);
}
}
In C++11, we can take advantage of expression SFINAE:
namespace details {
// the specialized case
template <class C, class K>
auto in_impl(C const& c, K const& key, int )
-> decltype(c.find(key), true) {
return c.find(key) != c.end();
}
// the general case
template <class C, class K>
bool in_impl(C const& c, K const& key, ...) {
using std::begin; using std::end;
return std::find(begin(c), end(c), key) != end(c);
}
}
template <class Container, class Key>
bool in(Container const& c, Key const& key) {
return details::in_impl(c, key, 0);
}
Note that in both cases we have the using std::begin; using std::end; two-step in order to handle all the standard containers, raw arrays, and any use-provided/adapted containers.
This gives you an infix *in* operator:
namespace notstd {
namespace ca_helper {
template<template<class...>class, class, class...>
struct can_apply:std::false_type{};
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class...Ts>
struct can_apply<Z,void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = ca_helper::can_apply<Z,void,Ts...>;
namespace find_helper {
template<class C, class T>
using dot_find_r = decltype(std::declval<C>().find(std::declval<T>()));
template<class C, class T>
using can_dot_find = can_apply< dot_find_r, C, T >;
template<class C, class T>
constexpr std::enable_if_t<can_dot_find<C&, T>{},bool>
find( C&& c, T&& t ) {
using std::end;
return c.find(std::forward<T>(t)) != end(c);
}
template<class C, class T>
constexpr std::enable_if_t<!can_dot_find<C&, T>{},bool>
find( C&& c, T&& t ) {
using std::begin; using std::end;
return std::find(begin(c), end(c), std::forward<T>(t)) != end(c);
}
template<class C, class T>
constexpr bool finder( C&& c, T&& t ) {
return find( std::forward<C>(c), std::forward<T>(t) );
}
}
template<class C, class T>
constexpr bool find( C&& c, T&& t ) {
return find_helper::finder( std::forward<C>(c), std::forward<T>(t) );
}
struct finder_t {
template<class C, class T>
constexpr bool operator()(C&& c, T&& t)const {
return find( std::forward<C>(c), std::forward<T>(t) );
}
constexpr finder_t() {}
};
constexpr finder_t finder{};
namespace named_operator {
template<class D>struct make_operator{make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
-> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
namespace in_helper {
struct in_t:notstd::named_operator::make_operator<in_t> {};
template<class T, class C>
bool named_invoke( T&& t, in_t, C&& c ) {
return ::notstd::find(std::forward<C>(c), std::forward<T>(t));
}
}
in_helper::in_t in;
}
On a flat container, like a vector array or string, it is O(n).
On an associative sorted container, like a std::map, std::set, it is O(lg(n)).
On an unordered associated container, like std::unordered_set, it is O(1).
Test code:
std::vector<int> v{1,2,3};
if (1 *in* v)
std::cout << "yes\n";
if (7 *in* v)
std::cout << "no\n";
std::map<std::string, std::string, std::less<>> m{
{"hello", "world"}
};
if ("hello" *in* m)
std::cout << "hello world\n";
Live example.
C++14, but mainly for enable_if_t.
So what is going on here?
Well, can_apply is a bit of code that lets me write can_dot_find, which detects (at compile time) if container.find(x) is a valid expression.
This lets me dispatch the searching code to use member-find if it exists. If it doesn't exist, a linear search using std::find is used instead.
Which is a bit of a lie. If you define a free function find(c, t) in the namespace of your container, it will use that rather than either of the above. But that is me being fancy (and it lets you extend 3rd party containers with *in* support).
That ADL (argument dependent lookup) extensibity (the 3rd party extension ability) is why we have three different functions named find, two in a helper namespace and one in notstd. You are intended to call notstd::find.
Next, we want a python-like in, and what is more python like than an infix operator? To do this in C++ you need to wrap your operator name in other operators. I chose *, so we get an infix *in* named operator.
TL;DR
You do using notstd::in; to import the named operator in.
After that, t *in* c first checks if find(t,c) is valid. If not, it checks if c.find(t) is valid. If that fails, it does a linear search of c using std::begin std::end and std::find.
This gives you very good performance on a wide variety of std containers.
The only thing it doesn't support is
if (7 *in* {1,2,3})
as operators (other than =) cannot deduce initializer lists I believe. You could get
if (7 *in* il(1,2,3))
to work.
I guess one might make use of this thread and create a custom version of in function.
The main idea is to use SFINAE (Substitution Failure Is Not An Error) to differentiate associative containers (which have key_type member) from sequence containers (which have no key_type member).
Here is a possible implementation:
namespace detail
{
template<typename, typename = void>
struct is_associative : std::false_type {};
template<typename T>
struct is_associative<T,
std::enable_if_t<sizeof(typename T::key_type) != 0>> : std::true_type {};
template<typename C, typename T>
auto in(const C& container, const T& value) ->
std::enable_if_t<is_associative<C>::value, bool>
{
using std::cend;
return container.find(value) != cend(container);
}
template<typename C, typename T>
auto in(const C& container, const T& value) ->
std::enable_if_t<!is_associative<C>::value, bool>
{
using std::cbegin;
using std::cend;
return std::find(cbegin(container), cend(container), value) != cend(container);
}
}
template<typename C, typename T>
auto in(const C& container, const T& value)
{
return detail::in(container, value);
}
Small usage example on WANDBOX.
You can use std::find from <algorithm>, but this works only for datatypes like: std::map and std::vector (etc).
Also note that this will return, iterator to the first element that is found equal to the value you pass, unlike the in operator in Python that returns a bool.
I think one of the nice features of the "in" operator in python is that it can be used with different data types (strings v/s strings, numbers v/s lists, etc).
I am developing a library for using python constructions in C++. It includes "in" and "not_in" operators.
It is based on the same technique used to implement the in operator posted in a previous answer, in which make_operator<in_t> is implemented. However, it is extended for handling more cases:
Searching a string inside a string
Searching an element inside vector and maps
It works by defining several overloads for a function: bool in__(T1 &v1, T2 &v2), in which T1 and T2 consider different possible types of objects. Also, overloads for a function: bool not_in__(T1 &v1, T2 &v2) are defined. Then, the operators "in" and "not_in" call those functions for working.
The implementation is in this repository:
https://github.com/ploncomi/python_like_cpp

How can I use C++11 variadic templates to define a vector-of-tuples backed by a tuple-of-vectors?

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.

C++ container/array/tuple consistent access interface

Is there, perhaps in boost, consistent element access semantics which works across containers?
something along the lines of:
element_of(std_pair).get<1>();
element_of(boost_tuple).get<0>();
element_of(pod_array).get<2>();
in principle i can write myself, but I would rather not reinvent the wheel.thanks
Containers have different ways of accessing them because they are inherently different. The closest that you get in the STL are iterators. All of the standard containers have iterators, so you can iterate over them and use the same algorithms on them using those iterators. However, what each iterator contains differs depending on the container (must just have the element, but maps have pairs). And if you're looking at pair as a container, it's not going to fit in with the rest because it doesn't have iterators.
In most cases, using iterators solves the problem. However, it obviously doesn't completely solve the problem, and the STL does not have a solution for it. Boost may, but I'm unaware of one.
The main point, however, is that containers are inherently different and to a great extent are not meant to be interchangeable. By using standard iterators, most containers can be swapped for one another fairly easily. But it doesn't generally make sense to swap one container for another without changing some of the code around it because they act so differently. I believe that Scott Meyers makes a point of this in his book "Effective STL."
If you're really trying to make the various containers interchangeable, I'd suggest rethinking that and looking more closely at what you're doing. Odds are that that's not the best idea. Now, it may very well be a good idea for your particular application - I certainly can't say without knowing anything about it, and you'd be the best judge of that - but in the general case, making containers truly interchangeable is a bad idea. Iterators make it possible to reuse many algorithms on them, but even there, the type of algorithms that you can use on a particular container varies depending on the type of iterators that that container uses (random access, bi-directional, etc.).
So, no, I'm not aware of a pre-existing solution for accessing container elements other than iterators, but generally speaking, I'd advise against attempting it. Containers are not truly interchangeable and are not meant to be.
I'm not aware of such a thing.
You could most probably just implement a free get function for the types you're interested in. Boost.Tuple already has it. std::pair has it in C++0x. And the rest shouldn't be too complicated.
E.g
#include <iostream>
#include <utility>
#include <vector>
#include <boost/tuple/tuple.hpp>
namespace getter
{
template <size_t Index, class Container>
typename Container::reference get(Container& c)
{
return c[Index];
}
template <size_t Index, class Container>
typename Container::const_reference get(const Container& c)
{
return c[Index];
}
template <size_t Index, class T>
T& get(T *arr)
{
return arr[Index];
}
namespace detail {
template <size_t Index, class T, class U>
struct PairTypeByIndex;
template <class T, class U>
struct PairTypeByIndex<0u, T, U>
{
typedef T type;
type& operator()(std::pair<T, U>& p) const { return p.first; }
const type& operator()(const std::pair<T, U>& p) const { return p.first; }
};
template <class T, class U>
struct PairTypeByIndex<1u, T, U>
{
typedef U type;
type& operator()(std::pair<T, U>& p) const { return p.second; }
const type& operator()(const std::pair<T, U>& p) const { return p.second; }
};
}
template <size_t Index, class T, class U>
typename detail::PairTypeByIndex<Index, T, U>::type& get(std::pair<T, U>& p)
{
return detail::PairTypeByIndex<Index, T, U>()(p);
}
template <size_t Index, class T, class U>
const typename detail::PairTypeByIndex<Index, T, U>::type& get(const std::pair<T, U>& p)
{
return detail::PairTypeByIndex<Index, T, U>()(p);
}
using boost::get;
}
int main()
{
boost::tuple<int, int> tuple(2, 3);
std::cout << getter::get<0>(tuple) << '\n';
std::vector<int> vec(10, 1); vec[2] = 100;
std::cout << getter::get<2>(vec) << '\n';
const int arr[] = {1, 2, 3, 4, 5};
std::cout << getter::get<4>(arr) << '\n';
std::pair<int, float> pair(41, 3.14);
++getter::get<0>(pair);
const std::pair<int, float> pair_ref = pair;
std::cout << getter::get<0>(pair_ref) << ' ' << getter::get<1>(pair_ref) << '\n';
}
I'm not aware of any generic accessors that would work across all known definitions of containers in C++. However, Boost.Range can be used as such to some extent.
For better flexibility, you will likely need to implement it yourself. Perhaps scratching something along this:
struct container_accessor { ... }
template <typename Container>
container_accessor make_accessor(Container& c) { ... }
template <typename Container>
container_const_accessor make_accessor(Container const& c) { ... }
where and then specialise container_accessor for all containers you need.

iterator adapter to iterate just the values in a map?

I'm just getting back into C++ after a couple of years of doing a lot of C#, and recently Objective C.
One thing I've done before is to roll my own iterator adapter for std::map that will deref to just the value part, rather than the key-value pair. This is quite a common and natural thing to do. C# provides this facility with its Keys and Values properties of its Dictionary class. Objective-C's NSDictionary, similarly, has allKeys and allValues.
Since I've been "away", Boost has acquired the Range and ForEach libraries, which I am now using extensively. I wondered if between the two there was some facility to do the same, but I haven't been able to find anything.
I'm thinking of knocking something up using Boost's iterator adapters, but before I go down that route I thought I'd ask here if anyone knows of such a facility in Boost, or somewhere else ready made?
Replacing the previous answer, in case anybody else finds this like I did. As of boost 1.43, there are some commonly used range adaptors provided. In this case, you want boost::adaptors::map_values. The relevant example:
http://www.boost.org/doc/libs/1_46_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html#range.reference.adaptors.reference.map_values.map_values_example
I don't think there's anything out of the box. You can use boost::make_transform.
template<typename T1, typename T2> T2& take_second(const std::pair<T1, T2> &a_pair)
{
return a_pair.second;
}
void run_map_value()
{
map<int,string> a_map;
a_map[0] = "zero";
a_map[1] = "one";
a_map[2] = "two";
copy( boost::make_transform_iterator(a_map.begin(), take_second<int, string>),
boost::make_transform_iterator(a_map.end(), take_second<int, string>),
ostream_iterator<string>(cout, "\n")
);
}
There is a boost range adaptor for exactly this purpose.
See http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html
(This example cribbed from there)
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::map<int,int> input;
for (int i = 0; i < 10; ++i)
input.insert(std::make_pair(i, i * 10));
boost::copy(
input | map_values,
std::ostream_iterator<int>(std::cout, ","));
return 0;
}
Continuing David's answer, there's another possibility to put the boile by creating a derived class from boost::transform_iterator. I'm using this solution in my projects:
namespace detail
{
template<bool IsConst, bool IsVolatile, typename T>
struct add_cv_if_c
{
typedef T type;
};
template<typename T>
struct add_cv_if_c<true, false, T>
{
typedef const T type;
};
template<typename T>
struct add_cv_if_c<false, true, T>
{
typedef volatile T type;
};
template<typename T>
struct add_cv_if_c<true, true, T>
{
typedef const volatile T type;
};
template<typename TestConst, typename TestVolatile, typename T>
struct add_cv_if: public add_cv_if_c<TestConst::value, TestVolatile::value, T>
{};
} // namespace detail
/** An unary function that accesses the member of class T specified in the MemberPtr template parameter.
The cv-qualification of T is preserved for MemberType
*/
template<typename T, typename MemberType, MemberType T::*MemberPtr>
struct access_member_f
{
// preserve cv-qualification of T for T::second_type
typedef typename detail::add_cv_if<
std::tr1::is_const<T>,
std::tr1::is_volatile<T>,
MemberType
>::type& result_type;
result_type operator ()(T& t) const
{
return t.*MemberPtr;
}
};
/** #short An iterator adaptor accessing the member called 'second' of the class the
iterator is pointing to.
*/
template<typename Iterator>
class accessing_second_iterator: public
boost::transform_iterator<
access_member_f<
// note: we use the Iterator's reference because this type
// is the cv-qualified iterated type (as opposed to value_type).
// We want to preserve the cv-qualification because the iterator
// might be a const_iterator e.g. iterating a const
// std::pair<> but std::pair<>::second_type isn't automatically
// const just because the pair is const - access_member_f is
// preserving the cv-qualification, otherwise compiler errors will
// be the result
typename std::tr1::remove_reference<
typename std::iterator_traits<Iterator>::reference
>::type,
typename std::iterator_traits<Iterator>::value_type::second_type,
&std::iterator_traits<Iterator>::value_type::second
>,
Iterator
>
{
typedef boost::transform_iterator<
access_member_f<
typename std::tr1::remove_reference<
typename std::iterator_traits<Iterator>::reference
>::type,
typename std::iterator_traits<Iterator>::value_type::second_type,
&std::iterator_traits<Iterator>::value_type::second
>,
Iterator
> baseclass;
public:
accessing_second_iterator():
baseclass()
{}
// note: allow implicit conversion from Iterator
accessing_second_iterator(Iterator it):
baseclass(it)
{}
};
This leads to even cleaner code:
void run_map_value()
{
typedef map<int, string> a_map_t;
a_map_t a_map;
a_map[0] = "zero";
a_map[1] = "one";
a_map[2] = "two";
typedef accessing_second_iterator<a_map_t::const_iterator> ia_t;
// note: specify the iterator adaptor type explicitly as template type, enabling
// implicit conversion from begin()/end()
copy<ia_t>(a_map.begin(), a_map.end(),
ostream_iterator<string>(cout, "\n")
);
}