HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Chain multiple containers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
containersmultiplechain

Problem

Python has itertools.chain(), but C++ has nothing. This is my attempt to implement such a thing. Looking mainly for comments about potentially smarter ways of doing things or potential pitfalls this code falls into based on its current implementation.

Currently, the objects that chain() will give back will be a reference if all the corresponding containers dereference to the same type, otherwise it will be a value (e.g. chaining a vector and deque will give an int&, but if the second was a deque instead would give an int).

First, some metaprogramming boilerplate:

namespace adl_details {
    using std::begin;
    using std::end;

    template 
    auto adl_begin(C&& c) {
        return begin(std::forward(c));
    }

    template 
    auto adl_end(C&& c) {
        return end(std::forward(c));
    }    
}

using adl_details::adl_begin;
using adl_details::adl_end;

template 
using iter_t = decltype(adl_begin(std::declval()));

template 
using iter_pair_t = std::pair, iter_t>;

template 
using deref_t = decltype(*std::declval>());

template 
struct type_is { using type = T; };

template 
struct nondecay_common_type;

template 
using nondecay_common_type_t = typename nondecay_common_type::type;

template 
struct nondecay_common_type : type_is { };

template 
T makeT();

template 
struct nondecay_common_type
: type_is() : std::declval>())>
{ };


(nondecay_common_type is necessary because std::common_type_t yields int but I want it to yield int&. makeT is necessary because if I use std::declval, std::common_type_t would yield int&& but I want it to yield int).

And now the main event:

```
template
class Chainer {
using sequence = std::make_index_sequence;
using deref_type = nondecay_common_type_t...>;

public:
Chainer(Containers&&... c)
: containers(std::forward(c)...)
{ }

class iterator
{
public:
iterator(iter_pair_t... pairs)
: iter_pairs(pairs...)
{ }

deref_ty

Solution

Try using ranges instead of iterators. E.g. using Eric Niebler's range-v3 library, you can write

#include 
#include 
#include 

int main()
{
    using namespace ranges;

    std::vector his_face{"this", "is", "his", "face"};
    std::vector another_mess{"another", "fine", "mess"};
    std::cout << view::concat(his_face, another_mess);
}


Live Example. Using Boost.Range, a similar result can be obtained, but it's not as clean as using range-v3.

Code Snippets

#include <iostream>
#include <vector>
#include <range/v3/view/concat.hpp>

int main()
{
    using namespace ranges;

    std::vector<std::string> his_face{"this", "is", "his", "face"};
    std::vector<std::string> another_mess{"another", "fine", "mess"};
    std::cout << view::concat(his_face, another_mess);
}

Context

StackExchange Code Review Q#105117, answer score: 3

Revisions (0)

No revisions yet.