This question already has answers here:
How can I print a list of elements separated by commas?
(34 answers)
Closed 2 years ago.
I'm trying to print a comma separated list of a single detail from a std::vector<MyClass>. So far the simplest and cleverest way I have seen to do this is to use
std::ostringstream ss;
std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<std::string>(ss, ", "))
ss << vec.back();
That worked fine when I was printing a vector of strings. However, now I am trying to print a single detail about MyClass. I know in Python I could do something like
(x.specific_detail for x in vec)
to get a generator expression for the thing that I am interested in. I'm wondering if I can do something similar here or if I am stuck doing
for (auto it = vec.begin(); it != vec.end(); ++it) {
// Do stuff here
}
One way of solving this I have seen is:
std::string separator;
for (auto x : vec) {
ss << separator << x.specific_detail;
separator = ",";
}
A fairly easy and reusable way:
#include <vector>
#include <iostream>
template<class Stream, class T, class A>
Stream& printem(Stream&os, std::vector<T, A> const& v)
{
auto emit = [&os, need_comma = false](T const& x) mutable
{
if (need_comma) os << ", ";
os << x;
need_comma = true;
};
for(T const& x : v) emit(x);
return os;
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
printem(std::cout, v) << std::endl;
}
And another way which defines an extendable protocol for printing containers:
#include <vector>
#include <iostream>
template<class Container>
struct container_printer;
// specialise for a class of container
template<class T, class A>
struct container_printer<std::vector<T, A>>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c) : c(c) {}
std::ostream& operator()(std::ostream& os) const
{
const char* sep = "";
for (const T& x : c) {
os << sep << x;
sep = ", ";
}
return os;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
};
template<class Container>
auto print_container(Container&& c)
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type>(c);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
std::cout << print_container(v) << std::endl;
}
...of course we can go further...
#include <vector>
#include <iostream>
template<class...Stuff>
struct container_printer;
// specialise for a class of container
template<class T, class A, class Separator, class Gap, class Prefix, class Postfix>
struct container_printer<std::vector<T, A>, Separator, Gap, Prefix, Postfix>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c, Separator sep, Gap gap, Prefix prefix, Postfix postfix)
: c(c)
, separator(sep)
, gap(gap)
, prefix(prefix)
, postfix(postfix) {}
std::ostream& operator()(std::ostream& os) const
{
Separator sep = gap;
os << prefix;
for (const T& x : c) {
os << sep << x;
sep = separator;
}
return os << gap << postfix;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
Separator separator;
Gap gap;
Prefix prefix;
Postfix postfix;
};
template<class Container, class Sep = char, class Gap = Sep, class Prefix = char, class Postfix = char>
auto print_container(Container&& c, Sep sep = ',', Gap gap = ' ', Prefix prefix = '[', Postfix postfix = ']')
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type, Sep, Gap, Prefix, Postfix>(c, sep, gap, prefix, postfix);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
// json-style
std::cout << print_container(v) << std::endl;
// custom
std::cout << print_container(v, " : ", " ", "(", ")") << std::endl;
// custom
std::cout << print_container(v, "-", "", ">>>", "<<<") << std::endl;
}
expected output:
[ 1,2,3,4,5 ]
( 1 : 2 : 3 : 4 : 5 )
>>>1-2-3-4-5<<<
Here's an example using std::transform:
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<std::string> strs = {"Testing", "One", "Two", "Three"};
if (!strs.empty())
{
std::copy(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << strs.back();
}
std::cout << '\n';
if (!strs.empty())
{
std::transform(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<size_t>(std::cout, ", "),
[](const std::string& str) { return str.size(); });
std::cout << strs.back().size();
}
std::cout << '\n';
}
Output:
Testing, One, Two, Three
7, 3, 3, 5
Here is a tiny simple range library:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
range_t without_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::next(b, n), e};
}
range_t without_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::prev(e, n)};
}
range_t only_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::next(b, n)};
}
range_t only_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::prev(end(), n), end()};
}
};
template<class It>
range_t<It> range(It s, It f) { return {s,f}; }
template<class C>
auto range(C&& c) {
using std::begin; using std::end;
return range( begin(c), end(c) );
}
now we are ready.
auto r = range(vec);
for (auto& front: r.only_front()) {
std::cout << front.x;
}
for (auto& rest: r.without_front()) {
std::cout << "," << rest.x;
}
Live example.
Now you can get fancier. boost transform iterators, together with boost range, let you do something similar to a list comprehension in python. Or Rangesv3 library for C++2a.
Writing a transform input iterator isn't amazingly hard, it is just a bunch of boilerplate. Simply look at the axioms of input iterator, write a type that stores an arbitrary iterator and forwards most methods to it.
It also stores some function. On * and ->, call the function on the dereferenced iterator.
template<class It, class F>
struct transform_iterator_t {
using reference=std::result_of_t<F const&(typename std::iterator_traits<It>::reference)>;
using value_type=reference;
using difference_type=std::ptrdiff_t;
using pointer=value_type*;
using iterator_category=std::input_iterator_tag;
using self=transform_iterator_t;
It it;
F f;
friend bool operator!=( self const& lhs, self const& rhs ) {
return lhs.it != rhs.it;
}
friend bool operator==( self const& lhs, self const& rhs ) {
return !(lhs!=rhs);
}
self& operator++() {
++it;
return *this;
}
self operator++(int) {
auto r = *this;
++*this;
return r;
}
reference operator*() const {
return f(*it);
}
pointer operator->() const {
// dangerous
return std::addressof( **this );
}
};
template<class F>
auto iterator_transformer( F&& f ) {
return [f=std::forward<F>(f)](auto it){
return transform_iterator_t<decltype(it), std::decay_t<decltype(f)>>{
std::move(it), f
};
};
}
template<class F>
auto range_transfromer( F&& f ) {
auto t = iterator_transformer(std::forward<F>(f));
return [t=std::move(t)](auto&&...args){
auto tmp = range( decltype(args)(args)... );
return range( t(tmp.begin()), t(tmp.end()) );
};
}
Live example of transformer.
And if we add -- we can even use ostream iterator.
Note that std::prev requires a bidirectional iterator, which requires forward iterator concept, which requires that the transform iterator return an actual reference, which is a pain.
You can use the exact code you already have, just change the type you pass to std::ostream_iterator to restrict its output:
class MyClassDetail {
const MyClass &m_cls;
public:
MyClassDetail(const MyClass &src) : m_cls(src) {}
friend std::ostream& operator<<(std::ostream &out, const MyClassDetail &in) {
return out << in.m_cls.specific_detail;
}
};
std::copy(vec.begin(), vec.end()-1, std::ostream_iterator<MyClassDetail>(ss, ", "));
ss << MyClassDetail(vec.back());
Live demo
Here's what was ultimately used
// assume std::vector<MyClass> vec
std::ostringstream ss;
std::for_each(vec.begin(), vec.end() - 1,
[&ss] (MyClass &item) {
ss << item.specific_detail << ", ";
}
);
ss << vec.back().specific_detail;
You can simply the exact same code, but define a operator<< overload:
ostream &operator<<(ostream& out)
{
out << m_detail;
}
Related
I have the following code to generate tuples of adjacent pairs in a range. This works for bidirectional ranges but not for forward only ranged.
template <typename Range>
// Returns a range of adjacent pairs of the input range
auto make_adjacent_range(Range const & r) -> decltype(boost::combine(
boost::make_iterator_range(boost::begin(r), boost::prior(boost::end(r))),
boost::make_iterator_range(boost::next(boost::begin(r)), boost::end(r))))
{
return boost::combine(
boost::make_iterator_range(boost::begin(r), boost::prior(boost::end(r))),
boost::make_iterator_range(boost::next(boost::begin(r)), boost::end(r)));
}
boost::prior is not accepted with a forward only range. Is there an equally elegant solution that will work with forward ranges?
boost::combine
Not really elegant, but you can just write a adjacent_iterator type.
It's relatively tricky to get it to work for InputIterator, as you have to dereference before each increment
template <typename InputIterator>
class adjacent_iterator
{
public:
using element_type = std::iterator_traits<InputIterator>::value_type;
using value_type = std::pair<element_type, element_type>;
using category = std::iterator_traits<InputIterator>::category;
// all the other typedefs
adjacent_iterator& operator++()
{
element.first = element.second;
if (needs_deref) element.second = *it;
++it;
needs_deref = true;
return *this;
}
reference operator*()
{
element.second = *it;
needs_deref = false;
return element;
}
// all the other members
friend bool operator==(adjacent_iterator lhs, adjacent_iterator rhs)
{
// only check the iterator
return lhs.it == rhs.it;
}
private:
adjacent_iterator(element_type first, InputIterator second)
: element(first, {}), it(second), needs_deref(true) {}
adjacent_iterator(InputIterator end)
: it(end) {}
InputIterator it;
value_type element;
bool needs_deref;
// not sure how to declare this friendship
template <typename Range>
friend auto make_adjacent_range(Range const & r)
{
auto begin = boost::begin(r);
auto end = boost::end(r);
using IT = decltype(boost::begin(r));
auto elem = *begin++;
auto b = adjacent_iterator<IT>(elem, begin);
auto e = adjacent_iterator<IT>(end);
return boost::make_iterator_range(b, e);
}
};
This works, but could be quite inefficient depending on the iterator types:
template <typename Range>
auto make_adjacent_range(Range const & r) {
auto n = boost::size(r);
auto b = boost::begin(r);
auto r1 = boost::make_iterator_range(b, boost::next(b, n-1));
auto r2 = r1;
r2.advance_begin(1);
r2.advance_end(1);
return boost::combine(r1, r2);
}
Live On Coliru
#include <boost/range.hpp>
#include <boost/range/combine.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <iostream>
#include <forward_list>
template <typename Range>
auto make_adjacent_range(Range const & r) {
auto n = boost::size(r);
auto b = boost::begin(r);
auto r1 = boost::make_iterator_range(b, boost::next(b, n-1));
auto r2 = r1;
r2.advance_begin(1);
r2.advance_end(1);
return boost::combine(r1, r2);
}
int main() {
std::forward_list<int> v{1,2,3,4};
for (auto p : make_adjacent_range(v))
std::cout << p.get<0>() << " " << p.get<1>() << "\n";
}
Prints
1 2
2 3
3 4
Perhaps it would be nicer to make an iterator adaptor.
I've learned a lot in the last couple of weeks about this stuff, but not enough. The code below compiles and runs but the code in TEST_ADAPT is incomplete, I'm not sure how to make the connection.
The object is to parse into a plane jane container that has no variant dependency. I have figured out I can get a tuple of references to my storage which spirit likes well enough. (see TEST_REF). The kleene operator is looking for a single sequential container but on a set of alternatives, that doesn't look to be possible. So I guess I need to hand it something that is a proxy for that container but has gear work to locate in a tuple the destination references.
I think it will be a great exercise for me to write this ContainerAdaptor even if it is the wrong way to approach this. So I'm wondering if I'm in right field or on the right track.
The best I know I can complete is to use the TEST_VECT method and make a pass over the vector to copy the data into my ALL container. But that's just not right.
Update:
I have made Target::All fusion adapted and made ContainerAdaptor partially functional. Enough so that the kleene operator accepts it. I should be able to connect to the Target::All object, maybe...
#include <iostream>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
//parse kleene operator to a set of alternatives, adaptor? with spirit x3
#define TEST_VECT
#define TEST_REF
#define TEST_ADAPT
// l.......................................................................
namespace Target {
struct Int
{
int int_val;
};
using IntVect = std::vector<Int>;
struct Word
{
std::string word_val;
};
using WordVect = std::vector<Word>;
struct All
{
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
BOOST_FUSION_ADAPT_STRUCT(Target::All, int_vect, word_vect)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
#define DEF_RULE( RuleName, Attr ) static auto const RuleName = rule<struct Attr##_def, Attr>( #RuleName )
namespace Target {
using namespace boost::spirit::x3;
auto const bare_word = lexeme[+char_("a-z")];
DEF_RULE(int_rule, Int) = int_;
DEF_RULE(word_rule, Word) = bare_word;
auto const int_vect_rule= "int" >> *int_rule;
auto const word_vect_rule= "word" >> *(word_rule - "int");
//another test
DEF_RULE(f_int_vect_rule, IntVect) = int_vect_rule;
DEF_RULE(f_word_vect_rule, IntVect) = word_vect_rule;
}//namespace Target
namespace Target {
struct Printer {
Printer(std::ostream& out) : out(out) {};
using result_type = void;
void operator()(const IntVect& expression) {
out << "IntVect: ";
for (auto& t : expression)
out << t << " ";
out << std::endl;
}
void operator()(const WordVect& expression) {
out << "Word: ";
for (auto& t : expression)
out << t << " ";
out << std::endl;
}
private:
std::ostream& out;
};
}//namespace Target
template<class Arg>
class ContainerAdaptor
{
public:
ContainerAdaptor(Arg& arg) :arg(arg) { }
typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;
typedef size_t size_type;
struct Vis : public boost::static_visitor<>
{
void operator()(const Target::IntVect & i) const
{
std::cout << i << std::endl;
}
void operator()(const Target::WordVect & i) const
{
std::cout << i << std::endl;
}
};
void insert(value_type* e, const value_type& v) {
std::cout << "haha! ";
boost::apply_visitor(Vis(), v);
}
value_type* end() { return nullptr; }
value_type* begin() { return nullptr; }
size_t size;
private:
Arg & arg;
};
int main()
{
using namespace Target;
std::string thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
std::string::iterator end = thestr.end();
#if defined(TEST_ADAPT)
{
std::cout << "\nTEST_ADAPT\n";
std::string::iterator begin = thestr.begin();
All all;
auto fwd = std::forward_as_tuple(all.word_vect, all.int_vect);
ContainerAdaptor<All>attr( all );
phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, attr);
Printer printer(std::cout);
}
#endif
#if defined(TEST_VECT)
{
std::cout << "TEST_VECT\n";
std::string::iterator begin = thestr.begin();
using Vars = variant<Target::IntVect, Target::WordVect>;
std::vector< Vars > a_vect;
bool r = phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, a_vect);
Printer printer(std::cout);
for (auto& i : a_vect)
i.apply_visitor(printer);
}
#endif
#if defined(TEST_REF)
{
std::cout << "\nTEST_REF\n";
std::string::iterator begin = thestr.begin();
All all;
auto fwd = std::forward_as_tuple(all.word_vect,all.int_vect);
phrase_parse(begin, end, word_vect_rule >> int_vect_rule, space, fwd);
Printer printer(std::cout);
std::_For_each_tuple_element(fwd, printer);
}
#endif
return 0;
}
The ContainerAdaptor Hack
Sufficiently simplified, it works:
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace Target {
using namespace boost::spirit::x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
template<class Arg> struct ContainerAdaptor
{
typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;
void insert(value_type* /*e*/, const value_type& v) {
std::cout << "haha! ";
struct Vis {
//using result_type = void;
void operator()(const Target::IntVect & i) const { std::cout << i << std::endl; }
void operator()(const Target::WordVect & i) const { std::cout << i << std::endl; }
};
boost::apply_visitor(Vis(), v);
}
value_type* end() { return nullptr; }
value_type* begin() { return nullptr; }
Arg & arg;
};
int main() {
using namespace Target;
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
All all;
ContainerAdaptor<All> attr { all };
if (phrase_parse(begin(thestr), end(thestr), *( int_vect_rule | word_vect_rule), space, attr)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints:
haha! test more
haha! 1 2 3 4
haha! this and that
haha! 5 4
haha! 99 22
Parsed:
Why Not Semantic Actions?
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace x3 = boost::spirit::x3;
namespace Target {
using namespace x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
int main() {
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
Target::All all;
struct {
Target::All& _r;
void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
} push_back { all };
auto unary = [](auto f) { return [f](auto& ctx) { return f(x3::_attr(ctx)); }; };
auto action = unary(push_back);
if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule[action] | Target::word_vect_rule[action]), x3::space)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints
Parsed:
1 2 3 4 5 4 99 22
test more this and that
Using Traits
Re-introducing the variant "value_type":
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<>
struct container_value<Target::All> {
using type = boost::variant<Target::IntVect, Target::WordVect>;
};
template<>
struct push_back_container<Target::All> {
template <typename V>
static bool call(Target::All& c, V&& v) {
struct {
Target::All& _r;
void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
} vis {c};
boost::apply_visitor(vis, v);
return true;
}
};
} } } }
namespace x3 = boost::spirit::x3;
namespace Target {
using namespace x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
int main() {
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
Target::All all;
if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule | Target::word_vect_rule), x3::space, all)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints
Parsed:
1 2 3 4 5 4 99 22
test more this and that
Is there a way to use for-range loop syntax to process two sequential elements in an array?
Example...
func( std::vector< vec2 > &points )
{
std::vector< float > distances;
for( int i = 0; i < (int)points.size() - 1; i++ )
{
auto from = points.at( i );
auto to = points.at( i + 1 );
distances.push_back( magnitude( to - from ) );
}
}
Is there a way to use for-range loop syntax to process two sequential elements in an array?
Not out of the box.
However, you can roll your own wrapper class and an iterator class to get what you need.
The begin() and end() member functions of the wrapper class must return an iterator which evaluates to a std::pair when it is dereferenced with the * operator.
Here's a demonstrative program:
#include <iostream>
#include <vector>
struct VectorWrapper;
struct MyIterator
{
MyIterator(VectorWrapper const& wrapper, size_t index) : wrapper_(wrapper), index_(index) {}
std::pair<float, float> operator*();
MyIterator& operator++()
{
++index_;
return *this;
}
bool operator==(MyIterator const& rhs) const
{
return (this->index_ == rhs.index_);
}
bool operator!=(MyIterator const& rhs) const
{
return (this->index_ != rhs.index_);
}
VectorWrapper const& wrapper_;
size_t index_;
};
struct VectorWrapper
{
explicit VectorWrapper(std::vector<float>& distances) : distances_(distances) {}
MyIterator begin() const
{
return MyIterator(*this, 0);
}
MyIterator end() const
{
return MyIterator(*this, distances_.size()-1);
}
std::vector<float>& distances_;
};
std::pair<float, float> MyIterator::operator*()
{
return std::make_pair(wrapper_.distances_[index_], wrapper_.distances_[index_+1]);
}
int main()
{
std::vector<float> dist = {1, 2, 3, 4, 5, 6};
VectorWrapper wrapper(dist);
for ( auto item : wrapper )
{
std::cout << item.first << ", " << item.second << std::endl;
}
}
and its output:
1, 2
2, 3
3, 4
4, 5
5, 6
In c++17 with a bit of library help, you can get this to work:
for (auto&&[ from, to ] : adjacent_overlapped_zip( points ) ) {
distances.push_back( magnitude( to-from) );
}
where adjacent_overlapped_zip returns a range of adpted iterators over pairs or tuples of points.
template<class It>
struct range {
It b; It e;
It begin() const{ return b; }
It end() const{ return e; }
bool empty() const{ return begin()==end(); }
range without_front( std::size_t n = 1 ) const {
return {std::next(begin(), n), end()};
}
range without_back( std::size_t n = 1 ) const {
return {begin(), std::prev(end(), n)};
}
};
template<class It>
range(It b, It e)->range<It>;
template<class It>
struct adjacent_iterator:It {
auto operator*()const {
return std::make_pair( It::operator*(), std::next(*this).It::operator*() );
}
using It::It;
explicit adjacent_iterator(It it):It(it) {}
};
template<class It>
explicit adjacent_iterator( It ) -> adjacent_iterator<It>;
// TODO: support pointers
template<class C>
auto adjacent_overlapped_zip( C& c ) {
using std::begin; using std::end;
range r( begin(c), end(c) );
if (!r.empty()) {
r = r.without_back();
range retval( adjacent_iterator(r.begin()), adjacent_iterator(r.end()) );
return retval;
} else {
return {};
}
}
or something like that. The above code probably contains typos and other errors.
I'd also be tempted by:
for (auto&&[ from, to ] : transform( [](auto it){ return std::make_pair( *it, *std::next(it)); }, range( iterators_of( points ) ).without_back() ) )
distances.push_back( magnitude( to-from) );
}
with a slightly fancier set of primitives. Ranges-v3 would make this even nicer.
In raw c++11, no you are out of luck.
I would like to translate the following traditional for loop into a C++11 for-each loop without extra looping constructs:
int a[] = { 5, 6, 7, 8, 9, 10 };
int b[] = { 50, 60, 70, 80, 90, 100 };
// Swap a and b array elements
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
a[i] ^= b[i]; b[i] ^= a[i]; a[i] ^= b[i];
}
Does there exist any way by which it is possible to provide more than one variable in the C++11 for-each loop like:
for (int i, int j : ...)
There is no built-in way to do this. If you can use Boost, boost::combine will work for iterating two (or more) ranges simultaneously (Does boost offer make_zip_range?, How can I iterate over two vectors simultaneously using BOOST_FOREACH?):
for (boost::tuple<int&, int&> ij : boost::combine(a, b)) {
int& i = boost::get<0>(ij);
int& j = boost::get<1>(ij);
// ...
}
Unfortunately accessing the elements within the tuple elements of the zipped range is highly verbose. C++17 will make this much more readable using structured binding:
for (auto [&i, &j] : boost::combine(a, b)) {
// ...
}
Since you don't need to break out of the loop or return from the enclosing function, you could use boost::range::for_each with the body of your loop as a lambda:
boost::range::for_each(a, b, [](int& i, int& j)
{
// ...
});
zip or combine ranges are common in many range libraries.
Writing one strong enough for a for(:) loop isn't hard however.
First we write a basic range type:
template<class It>
struct range_t {
It b,e;
It begin() const{ return b; }
It end() const{ return e; }
range_t without_front( std::size_t count = 1 ) const {
return {std::next(begin()), end()};
}
bool empty() const { return begin()==end(); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
template<class C>
auto range( C& c ) {
using std::begin; using std::end;
return range( begin(c), end(c) );
};
Then we write an iterator that works with ranges (easier than with iterators):
template<class R1, class R2>
struct double_foreach_iterator {
R1 r1;
R2 r2;
void operator++() { r1 = r1.without_front(); r2 = r2.without_front(); }
bool is_end() const { return r1.empty() || r2.empty(); }
auto operator*()const {
return std::tie( *r1.begin(), *r2.begin() );
}
using self=double_foreach_iterator;
auto cur() const {
return std::make_tuple( r1.begin(), r2.begin() );
}
friend bool operator==( self const& lhs, self const& rhs ) {
if (lhs.is_end() || rhs.is_end())
return lhs.is_end() == rhs.is_end();
return lhs.cur() == rhs.cur();
}
friend bool operator!=( self const& lhs, self const& rhs ) {
return !(lhs==rhs);
}
};
now we double iterate:
template<class A, class B>
auto zip_iterate(
A& a, B& b
) {
auto r1 = range(a);
auto r2 = range(b);
auto r1end = range(r1.end(), r1.end());
auto r2end = range(r2.end(), r2.end());
using it = double_foreach_iterator<decltype(r1), decltype(r2)>;
return range( it{r1, r2}, it{r1end, r2end} );
}
which gives us:
for (auto tup : zip_iterate(a, b)) {
int& i = std::get<0>(tup);
int& j = std::get<1>(tup);
// ...
}
or in C++17:
for (auto&& [i, j] : zip_iterate(a, b)) {
// ...
}
My zip iterate does not assume the two containers are of the same length, and will iterate to the length of the shorter one.
live example.
Just for fun.
The following isn't intended to be a serious answer to the question but just an exercise to try to understand the potentiality of C++11 (so, please, be patient).
The following is an example of a class (a draft of a class) that receive a couple of container (with size() method), with the same size (exception otherwise), and of a custom iterator that return a std::pair of std::reference_wrapper to n-position elements.
With a simple use example that show that it's possible to change the value in the starting containers.
Doesn't work with old C-style arrays but works with std::array. We're talking about C++11 so I suppose we could impose the use of std::array.
#include <array>
#include <vector>
#include <iostream>
#include <functional>
template <typename T1, typename T2>
class pairWrapper
{
public:
using V1 = typename std::remove_reference<decltype((T1().at(0)))>::type;
using V2 = typename std::remove_reference<decltype((T2().at(0)))>::type;
using RW1 = std::reference_wrapper<V1>;
using RW2 = std::reference_wrapper<V2>;
class it
{
public:
it (pairWrapper & pw0, std::size_t p0): pos{p0}, pw{pw0}
{ }
it & operator++ ()
{ ++pos; return *this; }
bool operator!= (const it & it0)
{ return pos != it0.pos; }
std::pair<RW1, RW2> & operator* ()
{
static std::pair<RW1, RW2>
p{std::ref(pw.t1[0]), std::ref(pw.t2[0])};
p.first = std::ref(pw.t1[pos]);
p.second = std::ref(pw.t2[pos]);
return p;
}
private:
std::size_t pos;
pairWrapper & pw;
};
it begin()
{ return it(*this, 0U); }
it end()
{ return it(*this, len); }
pairWrapper (T1 & t10, T2 & t20) : len{t10.size()}, t1{t10}, t2{t20}
{ if ( t20.size() != len ) throw std::logic_error("no same len"); }
private:
const std::size_t len;
T1 & t1;
T2 & t2;
};
template <typename T1, typename T2>
pairWrapper<T1, T2> makePairWrapper (T1 & t1, T2 & t2)
{ return pairWrapper<T1, T2>(t1, t2); }
int main()
{
std::vector<int> v1 { 1, 2, 3, 4 };
std::array<long, 4> v2 { { 11L, 22L, 33L, 44L } };
for ( auto & p : makePairWrapper(v1, v2) )
{
std::cout << '{' << p.first << ", " << p.second << '}' << std::endl;
p.first += 3;
p.second += 55;
}
for ( const auto & i : v1 )
std::cout << '[' << i << ']' << std::endl;
for ( const auto & l : v2 )
std::cout << '[' << l << ']' << std::endl;
return 0;
}
p.s.: sorry for my bad English
C++11 hasn't range-based-loop for ranged integral sequence.
for(auto e : {0..10} ) // wouldn't compile!!!
So I just decided simulate it.
template< class T , bool enable = std::is_integral<T>::value >
struct range_impl
{
struct iterator
{
constexpr T operator * ()const noexcept { return value; }
iterator& operator ++()noexcept { ++value; return *this; }
friend
constexpr bool operator != (const iterator & lhs, const iterator rhs ) noexcept
{
return lhs.value != rhs.value;
}
T value;
};
constexpr iterator begin()const noexcept { return { first }; }
constexpr iterator end ()const noexcept { return { last }; }
T first;
T last ;
};
template< class T >
range_impl<T> range(T first , T last) noexcept
{
return {first, last};
}
int main(){
// print numbers in [ 0..10 ), i.e. 0 1 2 3 4 5 6 7 8 9
for(auto e : range(0,10) ) std::cout << e << ' ';
std::cout << std::endl;
}
Q: How to generalize this method for ForwardIterators?
example:
template< class ForwardIterator, class T >
bool find(ForwardIterator first, ForwardIterator last, T const& value)
{
for(auto e: range(first, last) ) if (e == v) return true;
return false;
}
Specialization
template< class Iterator>
struct range_impl<Iterator, false>
{
range_impl(Iterator first, Iterator last)
: first(first), last(last)
{}
constexpr Iterator begin()const noexcept { return { first }; }
constexpr Iterator end ()const noexcept { return { last }; }
Iterator first;
Iterator last ;
};
Test:
int main(){
for(auto e : range(0,10) ) std::cout << e << ' ';
std::cout << std::endl;
const char* a[] = { "Say", "hello", "to", "the", "world" };
for(auto e : range(a, a + 5) ) std::cout << e << ' ';
std::cout << std::endl;
}
You are trying to reimplement boost::iterator_range and boost::counting_iterator. Simply do this instead:
template< class T >
boost::iterator_range< boost::counting_iterator<T> > range( T const& tBegin, T const& tEnd ) {
return boost::iterator_range< boost::counting_iterator<T> >( tBegin, tEnd );
}
There even exists a boost::counting_range already: http://www.boost.org/doc/libs/1_47_0/libs/range/doc/html/range/reference/ranges/counting_range.html