I'm trying to come up with an idomatic way of writing this
boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
boost::gregorian::date end(2000,12,31);
int i = 0;
while(start <= end) {
boost::gregorian::gregorian_calendar::day_of_week_type x = (*start).day_of_week();
if(x==0)
++i;
}
This is fine, but I wondered if there was a way of writing it like
boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
boost::gregorian::month_iterator end(boost::gregorian::date(2000,12,31));
const int i = std::count_if(start,end,[](boost::gregorian::month_iterator& start) {
boost::gregorian::gregorian_calendar::day_of_week_type x = (*start).day_of_week();
return (x==0);
});
Same result, but I think it's prettier code, it's more like a functional approach (which I like) and the intention of what I'm trying to achieve is clearer.
I have a feeling I have to use any_range<> but I'm not really sure how in this case as the month_iterator doesn't seem to have all the normal semantics of forward iterators
There is no simple way to do this. Firstly you should specialize std::iterator_traits for example like this
namespace std {
template<>
struct iterator_traits<boost::gregorian::month_iterator>
{
typedef ptrdiff_t difference_type;
typedef boost::gregorian::month_iterator value_type;
typedef boost::gregorian::month_iterator& reference;
typedef boost::gregorian::month_iterator* pointer;
};
}
Secondly, you cannot use any boost::range since there is no operator == for two iterators and there is no operator * const. So, you should write your own class, probably derived from boost::iterator_adaptor, however, I think, this iterator is simply not created for such usage.
I'm writing small example, which is not effective, but it works and there is no excessively complexity.
#include <boost/range.hpp>
#include <boost/range/any_range.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace std {
template<>
struct iterator_traits<boost::gregorian::month_iterator>
{
typedef ptrdiff_t difference_type;
typedef boost::gregorian::month_iterator value_type;
typedef boost::gregorian::month_iterator& reference;
typedef boost::gregorian::month_iterator* pointer;
};
}
class month_iterator : public boost::iterator_adaptor
<
month_iterator,
boost::gregorian::month_iterator*,
boost::gregorian::month_iterator::value_type,
boost::bidirectional_traversal_tag,
boost::gregorian::month_iterator::value_type&
>
{
friend class boost::iterator_core_access;
public:
month_iterator() : m_it(boost::gregorian::date(boost::gregorian::not_a_date_time)) {}
explicit month_iterator(const boost::gregorian::month_iterator& pos) :
m_it(pos)
{
receive_value();
}
reference dereference() const
{
return *value;
}
bool equal(const month_iterator& rhs) const
{
return *value >= *rhs.value;
}
void increment()
{
++m_it;
*this = month_iterator(m_it);
}
private:
void receive_value()
{
value.reset(new value_type(*m_it));
}
boost::gregorian::month_iterator m_it;
boost::shared_ptr<value_type> value;
};
int main()
{
boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
boost::gregorian::month_iterator end(boost::gregorian::date(2000,12,31));
month_iterator p(start), e(end);
const int result = std::count_if(p, e, [](const month_iterator::value_type& v)
{
return v.day_of_week() == 0;
});
std::cout << result << std::endl;
}
Related
I have a std::array of class A, class A has a data member num_, I want to init a std::vector with all the num_ from the std::array is there a way to do it?. I know that I can loop over it and assign manually, I want to know if there is a way to do it like in my code snippet.
this is what I tried:
#include <iostream>
#include <vector>
#include <array>
class A{
public:
A():num_{0}{}
int num_;
};
int main()
{
std::array<A, 5> arr;
for(int i = 0; i<5; ++i)
{
arr[i].num_ = i;
}
std::vector<int> vec(arr.begin()->num_,arr.end()->num_);
for(auto& i : vec)
{
std::cout << i << " ";
}
return 0;
}
What you want can be done by using a projection iterator: an iterator implemented in terms of another iterator and a projection function - upon access the projection gets applied. For example, using std::ranges::views::transform() (of course, this requires C++20):
#include <ranges>
#include <iostream>
#include <vector>
#include <array>
class A{
public:
A():num_{0}{}
int num_;
};
int main()
{
std::array<A, 5> arr;
for(int i = 0; i<5; ++i)
{
arr[i].num_ = i;
}
auto view = std::ranges::views::transform(arr, [](auto& x){ return x.num_; });
std::vector<int> vec(view.begin(), view.end());
for(auto& i : vec)
{
std::cout << i << " ";
}
return 0;
}
With pre-C++20 the easiest approach to get a std::vector populated with the projected values is probably to not populate the std::vector during construction but rather to populate it via an std::back_inserter (as #john has pointed out in a comment):
std::transform(arr.begin(), arr.end(), std::back_inserter(vec),
[](A& a)->int& { return a.num_; });
To use construction it is necessary to build an iterator doing the relevant projection. It seems std::vector requires homogenous iterator for the begin and end which effectively means that some sort of view needs to be build which provides suitable begin and end iterator. Here is a basic version of this approach:
#include <iostream>
#include <optional>
#include <vector>
#include <array>
#include <type_traits>
class A{
public:
A():num_{0}{}
int num_;
};
template <typename FwdIt, typename Fun>
class projection_iterator
{
mutable FwdIt it;
mutable std::optional<Fun> fun;
public:
using value_type = std::decay_t<decltype(std::declval<Fun>()(*std::declval<FwdIt>()))>;
using reference = value_type&;
using pointer = value_type*;
using difference_type = typename std::iterator_traits<FwdIt>::difference_type;
using iterator_category = std::forward_iterator_tag;
projection_iterator(): it(), fun(fun) {}
projection_iterator(FwdIt it, Fun fun): it(it), fun(fun) {}
reference operator*() const { return (*this->fun)(*this->it); }
pointer operator->() const { return &(*this->fun)(*this->it); }
projection_iterator& operator++() { ++this->it; return *this; }
projection_iterator operator++(int) { auto rc(*this); ++this->it; return rc; }
bool operator== (projection_iterator const& other) const { return this->it == other.it; }
bool operator!= (projection_iterator const& other) const { return this->it != other.it; }
bool operator== (FwdIt const& other) const { return this->it == other; }
bool operator!= (FwdIt const& other) const { return this->it != other; }
};
template <typename Range, typename Fun>
class project_range {
Range& range;
Fun fun;
template <typename FwdIt>
static auto make(FwdIt it, Fun fun) {
return projection_iterator<FwdIt, Fun>(it, fun);
}
public:
project_range(Range& range, Fun fun): range(range), fun(fun) {}
project_range(std::decay_t<Range>&&, Fun) = delete;
auto begin() { return make(range.begin(), fun); }
auto end() { return make(range.end(), fun); }
};
template <typename Range, typename Fun>
auto project(Range&& range, Fun fun) {
return project_range<Range, Fun>(range, fun);
}
int main()
{
std::array<A, 5> arr;
for(int i = 0; i<5; ++i)
{
arr[i].num_ = i;
}
auto p = project(arr, [](A& x)->int& { return x.num_; });
std::vector<int> vec(p.begin(), p.end());
for(auto& i : vec)
{
std::cout << i << " ";
}
return 0;
}
Unless absolutely necessary I wouldn't bother going down that route with pre-C++20 compilers.
Say I have a struct:
struct Boundary {
int top;
int left;
int bottom;
int right;
}
and a vector
std::vector<Boundary> boundaries;
What would be the most C++ style way to access the structs to get the sum of top, left, bottom and right separately?
I could write a loop like
for (auto boundary: boundaries) {
sum_top+=boundary.top;
sum_bottom+=boundary.bottom;
...
}
This seems like a lot of repetition. Of course I could do this instead:
std::vector<std::vector<int>> boundaries;
for (auto boundary: boundaries) {
for(size_t i=0; i<boundary.size();i++) {
sums.at(i)+=boundary.at(i)
}
}
But then I'd loose all the meaningful struct member names. Is there a way so that I can write a something like the following function:
sum_top=make_sum(boundaries,"top");
Reflection does not seem to be an option in C++. I am open to use C++ up to Version 14.
std::accumulate(boundaries.begin(), boundaries.end(), 0,
[](Boundary const & a, Boundary const & b) { return a.top + b.top); });
(IIRC the Boundary const &'s can be auto'd in C++17)
This doesn't make it generic for the particular element, which - indeed, due to the lack of reflection - isn't easy to generalize.
There are a few ways to ease your pain, though;
You could use a pointer-to-member, which is fine for your szenario but not very c-plusplus-y:
int Sum(vector<Boundary>const & v, int Boundary::*pMember)
{
return std::accumulate( /*...*/,
[&](Boundary const & a, Boundary const & b)
{
return a.*pMember + b.*pMember;
});
}
int topSum = Sum(boundaries, &Boundary::top);
(For pointer-to-member, see e.g. here: Pointer to class data member "::*")
You could also make this generic (any container, any member type), and you could also replace the pointer-to-member with a lambda (also allowing member functions)
You can achieve the desired effect with Boost Hana reflection:
#include <iostream>
#include <vector>
#include <boost/hana.hpp>
struct Boundary {
BOOST_HANA_DEFINE_STRUCT(Boundary,
(int, top),
(int, left),
(int, bottom),
(int, right)
);
};
template<class C, class Name>
int make_sum(C const& c, Name name) {
int sum = 0;
for(auto const& elem : c) {
auto& member = boost::hana::at_key(elem, name);
sum += member;
}
return sum;
}
int main() {
std::vector<Boundary> v{{0,0,1,1}, {1,1,2,2}};
std::cout << make_sum(v, BOOST_HANA_STRING("top")) << '\n';
std::cout << make_sum(v, BOOST_HANA_STRING("bottom")) << '\n';
}
See Introspecting user-defined types for more details.
I am probably a bit late to the party, but I wanted to add answer inspired by the one of #TobiasRibizel. Instead of adding much boilerplate code to your struct we add more boilerplate code once in the form of an iterator over (specified) members of a struct.
#include <iostream>
#include <string>
#include <map>
template<class C, typename T, T C::* ...members>
class struct_it {
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = std::bidirectional_iterator_tag;
constexpr struct_it (C &c) : _index{0}, _c(c)
{}
constexpr struct_it (size_t index, C &c) : _index{index}, _c(c)
{}
constexpr static struct_it make_end(C &c) {
return struct_it(sizeof...(members), c);
}
constexpr bool operator==(const struct_it& other) const {
return other._index == _index; // Does not check for other._c == _c, since that is not always possible. Maybe do &other._c == &_c?
}
constexpr bool operator!=(const struct_it& other) const {
return !(other == *this);
}
constexpr T& operator*() const {
return _c.*_members[_index];
}
constexpr T* operator->() const {
return &(_c.*_members[_index]);
}
constexpr struct_it& operator--() {
--_index;
return *this;
}
constexpr struct_it& operator--(int) {
auto copy = *this;
--_index;
return copy;
}
constexpr struct_it& operator++() {
++_index;
return *this;
}
constexpr struct_it& operator++(int) {
auto copy = *this;
++_index;
return copy;
}
private:
size_t _index;
C &_c;
std::array<T C::*, sizeof...(members)> _members = {members...}; // Make constexpr static on C++17
};
template<class C, typename T, T C::* ...members>
using cstruct_it = struct_it<const C, T, members...>;
struct boundary {
int top;
int bottom;
int left;
int right;
using iter = struct_it<boundary, int, &boundary::top, &boundary::bottom, &boundary::left, &boundary::right>;
using citer = cstruct_it<boundary, int, &boundary::top, &boundary::bottom, &boundary::left, &boundary::right>;
iter begin() {
return iter{*this};
}
iter end() {
return iter::make_end(*this);
}
citer cbegin() const {
return citer{*this};
}
citer cend() const {
return citer::make_end(*this);
}
};
int main() {
boundary b{1,2,3,4};
for(auto i: b) {
std::cout << i << ' '; // Prints 1 2 3 4
}
std::cout << '\n';
}
It works on C++14, on C++11 the constexpr functions are all const by default so they don't work, but just getting rid of the constexpr should do the trick. The nice thing is that you can choose just some members of your struct and iterate over them. If you have the same few members that you will always iterate over, you can just add a using. That is why I chose to make the pointer-to-members part of the template, even if it is actually not necessary, since I think that only the iterators over the same members should be of the same type.
One could also leave that be, replace the std::array by an std::vector and choose at runtime over which members to iterate.
Without going too much into the memory layout of C++ objects, I would propose replacing the members by 'reference-getters', which adds some boilerplate code to the struct, but except for replacing top by top() doesn't require any changes in the way you use the struct members.
struct Boundary {
std::array<int, 4> coordinates;
int& top() { return coordinates[0]; }
const int& top() const { return coordinates[0]; }
// ...
}
Boundary sum{};
for (auto b : boundaries) {
for (auto i = 0; i < 4; ++i) {
sum.coordinates[i] += b.coordinates[i];
}
}
This code is adopted from the boost multi-index "mru" example:
http://www.boost.org/doc/libs/1_46_1/libs/multi_index/example/serialization.cpp
I have code that is doing something similiar as a boost::unordered_map, but I would really like to add the mru functionality from this example.
I would like to make this code work as close to having a boost::unordered_map as possible. The key feature for me is the [] operator of the unordered_map.
The final lines of main() are broken and above each line as a comment is my question.
Thanks in advance to all answers comments.
#include <algorithm>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <iostream>
using namespace boost::multi_index;
class my_struct {
public:
my_struct(int in_a, std::string in_b) : a(in_a), b(in_b) {}
int a;
std::string b;
bool operator==(const my_struct &rhs) const
{
return (a == rhs.a);
}
bool operator!=(const my_struct &rhs) const
{
return !(*this == rhs);
}
friend std::ostream& operator<<(std::ostream &out, const my_struct&ms);
};
std::ostream& operator<<(std::ostream &out, my_struct &ms)
{
out << ms.a << " " << ms.b << std::endl;
return out;
}
inline std::size_t
hash_value(const my_struct &val)
{
return boost::hash_value(val.a);
}
// tags for multi_index
struct umap {};
template <typename Item>
class mru_list
{
typedef multi_index_container<
Item,
indexed_by<
sequenced<>,
hashed_unique<boost::multi_index::tag<umap>, identity<Item> >
>
> item_list;
public:
typedef Item item_type;
typedef typename item_list::iterator iterator;
mru_list(std::size_t max_num_items_):max_num_items(max_num_items_){}
void insert(const item_type& item)
{
std::pair<iterator,bool> p=il.push_front(item);
if(!p.second){ /* duplicate item */
il.relocate(il.begin(),p.first); /* put in front */
}
else if(il.size()>max_num_items){ /* keep the length <= max_num_items */
il.pop_back();
}
}
iterator begin(){return il.begin();}
iterator end(){return il.end();}
//private:
item_list il;
std::size_t max_num_items;
};
int main()
{
mru_list<my_struct> mru(10);
my_struct one(1, "One");
mru.insert(one);
mru.insert(my_struct(2, "Two"));
mru.insert(my_struct(3, "Three"));
mru.insert(one);
std::cout<<"most recently entered terms:"<<std::endl;
for (mru_list<my_struct>::iterator itr = mru.begin(); itr != mru.end(); ++itr) {
std::cout << itr->a << std::endl;
}
// what is my return type?
mru.il.get<umap>();
// Why doesn't this work?
mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);
// Why doesn't this have a [] operator like boost:unordered_map
mru.il.get<umap>()[1] = "foobar";
return 0;
}
// what is my return type?
mru.il.get<umap>();
Its return type is the type of your umap index, which is:
typedef typename boost::multi_index::index<
item_list
, umap
>::type hashed_index_t;
mru_list<my_struct>::hashed_index_t& hashed_index = mru.il.get<umap>();
In C++11 it is easier with auto:
auto& hashed_index = mru.il.get<umap>();
// Why doesn't this work?
mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);
find() returns an iterator of umap (second) index and the above statement is assigning it to the iterator of the first index. There are projection operations to convert from one index iterator type to another iterator type of the same multi-index container, e.g.:
mru_list<my_struct>::iterator itr = project<0>(mru.il, hashed_index.find(one));
// Why doesn't this have a [] operator like boost:unordered_map
Can't say why, it just doesn't.
So I'm trying to write a base class to handle classes that wrap std::vector, which I have working up to defining the __iter__ function. My first approach, and the one I wish to get working, is to have the begin() and end() functions in the base class. Doing this compiles fine, but when I run the code in python I get an error that looks simiar to:
Boost.Python.ArgumentError: Python argument types in
Container.__iter__(Container)
did not match C++ signature:
__iter__(boost::python::back_reference< stl_iter< std::vector< std::shared_ptr< K > > std::allocator< std::shared_ptr< K > > > >&>)
The following sample extension can be tested with
from test import *
c = Container()
for i in range(10):
c.append(K(str(i)))
for i in c:
print i
Sample extension:
#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T>
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
typedef typename T::value_type V;
typedef typename T::iterator iter;
virtual T& get_vector()=0;
public:
virtual ~stl_iter() {}
virtual void append(V item) {
get_vector().push_back(item);
}
virtual iter begin() {
return get_vector().begin();
}
virtual iter end() {
return get_vector().end();
}
};
class K {
std::string val;
public:
K(std::string s) : val(s) {}
std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
vK items;
protected:
vK& get_vector() { return items; }
public:
// Works if I uncomment these
//vK::iterator begin() { return get_vector().begin(); }
//vK::iterator end() { return get_vector().end(); }
public:
virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
using namespace boost::python;
class_<K, pK>("K", init<std::string>())
.def("__str__", &K::get_val)
;
class_<Container, pContainer>("Container")
.def("append", &Container::append)
.def("__iter__", range(&Container::begin, &Container::end))
;
}
The answer was actually quite simple: make the container behave like an stl container, and then to use boost's iterator<>() function instead of range().
To do this, I had to make the typedefs in stl_iter public, and to rename them to value_type and iterator.
Heres the updated C++ code.
#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T>
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
virtual T& get_vector()=0;
public:
// Next two lines changed, and made public
typedef typename T::value_type value_type;
typedef typename T::iterator iterator;
virtual ~stl_iter() {}
virtual void append(value_type item) {
get_vector().push_back(item);
}
virtual iterator begin() {
return get_vector().begin();
}
virtual iterator end() {
return get_vector().end();
}
};
class K {
std::string val;
public:
K(std::string s) : val(s) {}
std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
vK items;
protected:
vK& get_vector() { return items; }
public:
virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
using namespace boost::python;
class_<K, pK>("K", init<std::string>())
.def("__str__", &K::get_val)
;
class_<Container, pContainer>("Container")
.def("append", &Container::append)
// Use iterator() instead of range()
.def("__iter__", iterator<Container>())
;
}
range() also can be used fine, but underlying iterator anyway should support STL semantic, here is sample:
...
.def("__iter__"
, range<return_value_policy<copy_non_const_reference> >(
&my_sequence<heavy>::begin
, &my_sequence<heavy>::end))
I have a class Foo that contains a map and provides begin() and end() functions to iterate over it:
class Foo {
typedef std::map<int, double> Container;
typedef Container::const_iterator const_iterator;
Container c_;
public:
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
void insert(int i, double d) { c_[i] = d; }
// ...
};
Now I would like to change it internally from std::map<int, double> to just a std::set<int>, but I don't want to break any client code.
So the double d in the insert function would now just be ignored. And the following code should still be valid, where it->second will now just always be 0.0:
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
How can I make these changes in the Foo class?
In other words, how can I provide a Foo::const_iterator that adapts the new internal std::set<int>::const_iterator to behave like the old std::map<int,double>::const_iterator?
UPDATE: The reason I want to get rid of the map is memory efficiency. I have millions of Foo instances and cannot afford to store the double values in them.
Would using
std::set<std::pair<int, double> >
not be sufficient for this comparability?
Failing that you can always write your own iterator which wraps the std::list iterator and provides first and second members. Basically your operator++ would call operator++ on the real iterator etc. and the de-referencing operator could return either a temporary std::pair (by value) or a reference to a std::pair that lives within the iterator itself (if your legacy code can deal with that).
Update, slightly contrived example, might work depending on your scenario:
#include <iostream>
#include <set>
class Foo {
typedef std::set<int> Container;
typedef Container::const_iterator legacy_iterator;
Container c_;
// legacy iterator doesn't have a virtual destructor (probably?), shouldn't
// be a problem for sane usage though
class compat_iterator : public legacy_iterator {
public:
compat_iterator(const legacy_iterator& it) : legacy_iterator(it) {
}
const std::pair<int,double> *operator->() const {
static std::pair<int,double> value;
value = std::make_pair(**this, 0.0);
// Not meeting the usual semantics!
return &value;
}
};
public:
typedef compat_iterator const_iterator;
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
};
int main() {
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
}
How about something like this?
#include <iostream>
#include <map>
#include <set>
struct Funky
{
int first;
static const double second;
Funky(int i)
: first(i)
{}
};
const double Funky::second = 0.0;
bool operator<(const Funky& lhs, const Funky& rhs)
{
return lhs.first < rhs.first;
}
class Foo
{
private:
//std::map<int,double> m_data;
std::set<Funky> m_data;
public:
//typedef std::map<int,double>::const_iterator const_iterator;
typedef std::set<Funky>::const_iterator const_iterator;
const_iterator begin() const
{
return m_data.begin();
}
const_iterator end() const
{
return m_data.end();
}
void insert(int i, double d)
{
//m_data.insert(std::make_pair(i, d));
m_data.insert(i);
}
};
int main()
{
Foo foo;
foo.insert(23, 9.0);
for(Foo::const_iterator it=foo.begin(), iend=foo.end(); it!=iend; ++it)
{
std::cout << it->first << ' ' << it->second << '\n';
}
return 0;
}
Perhaps something along the lines of
operator int()(const std::pair<int, double>& p) const {
return p.first;
}
maybe within some wrapper?
Perhaps you can define a fake_pair class that implements first and second and put a set<fake_pair> inside Foo.
You can't, not completely. The problem is you are changing your interface, which will always break your clients. I would recommend you create two new functions of newBegin and newEnd (or similar) which has your new behaviour. Your old interface you keep this the same but mark it as depreciated. The implementation of this old interface can use one of the work around described by the others.