Boost::python and iterators from base class virtual functions - c++

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))

Related

How to initialise custom vector type with a standard vector

I have created a sample container which internally stores in a std::vector. I want to be able to initialise the container with a std::vector. So I created constructors that take a std::initializer_list and also taking a begin and end.
But I can't seem to initialise like this:
const std::vector< uint8_t > vec1 { 1,2,3,4,5 };
UsingVectorExample ex{ vec1.begin(), vec1.end() }; // compilation errors on this line
What is the problem here? and how can I fix?
The code is here:
#include <vector>
#include <cstdint>
class UsingVectorExample
{
public:
class iterator : public std::vector<uint8_t>::iterator
{
public:
explicit iterator(typename std::vector<uint8_t>::iterator c)
: std::vector<uint8_t>::iterator(c)
{}
};
class const_iterator : public std::vector<uint8_t>::const_iterator
{
public:
explicit const_iterator(typename std::vector<uint8_t>::const_iterator c)
: std::vector<uint8_t>::const_iterator(c)
{}
};
explicit UsingVectorExample(std::initializer_list<uint8_t> list)
: m_vector(list.size())
{
m_vector.assign(list);
}
UsingVectorExample(iterator begin, iterator end)
: m_vector(begin, end)
{}
UsingVectorExample(const_iterator begin, const_iterator end)
: m_vector(begin, end)
{}
iterator begin()
{
return iterator(m_vector.begin());
}
iterator end()
{
return iterator(m_vector.end());
}
const_iterator begin() const
{
return const_iterator(m_vector.begin());
}
const_iterator end() const
{
return const_iterator(m_vector.end());
}
void push_back(const uint8_t& val)
{
m_vector.push_back(val);
}
private:
std::vector<uint8_t> m_vector;
};
int main() {
const std::vector< uint8_t > vec1 { 1,2,3,4,5 };
UsingVectorExample ex{ vec1.begin(), vec1.end() }; // compilation errors on this line
}
The problem here is that your iterator constrcutors are explicit. That means vec1.begin() can't be converted to a UsingVectorExample::const_iterator without you doing it explicitly like
UsingVectorExample ex{ UsingVectorExample::const_iterator{vec1.begin()},
UsingVectorExample::const_iterator{vec1.end()} };
To not have to do that, just remove the explicit. You can see that working in this live example

C++ discourages base class of collection - is there anyway to fake it?

There are no similar concept of (Java) Collection in C++.
I can understand the reason, but I want to know whether there is any way to fake it elegantly.
Example
I have implemented many custom Collections.
They all have Iterator that works correctly, similar to std::vector, std::unordered_set, etc.
They are MyArray<T> , MyBinaryTree<T> and MySet<T>.
Here I will show a working code that show the location I want to fake it.
Let's say that I have 2 levels of program : library and user.
It does only one thing - User commands Library to eat all Orange*s in a bucket.
Library.h
class Library{
public: static void eatAll(const MyArray<Orange*>& bucket);
};
Library.cpp
#include "Orange.h"
void Library::eatAll(const MyArray<Orange*>& bucket){
for(auto orange:bucket){
orange->eaten();
}
}
User.h
MyArray<Orange*> bucket;
Library::eatAll(bucket);
It is OK.
Now, I want Library::eatAll to also support MyBinaryTree<Orange*>, I have some not-so-desirable approaches as below.
My poor solution
1. Java way
Make MyBinaryTree<T> and MyArray<Orange*> (and their iterator) inherit from a new class Collection<T> (and CollectionIterator<T>).
change signature to Library::eatAll(const Collection<T>&)
Disadvantage : performance penalty from "virtual" of some functions in Collection<T>.
2. Template v1
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
orange->eaten();
}
}
make eatAll a template function
Disadvantage : The implementation of the eatAll must be in header.
I have to #include orange.h in Library.h.
Sometimes, I really want to just forward declaration.
3. Template v2
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
eatAnOrange(orange)
}
}
private: void eatAnOrange(Orange* orange){
//below implementation is inside Library.cpp
orange->eaten();
}
create a middle-man function eatAnOrange
Disadvantage :
Code is less readable, not concise, cause a little maintainability problem.
If there are a lot of other functions e.g. squeezeAll(), I probably have to create a lot of middle-man functions, e.g. squeezeAnOrange().
4. Operator=()
Create converter among the 3 collection classes via implicit constructor.
Disadvantage : Suffer performance from creating a new instance of collection.
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
I believe my solutions are inelegant.
Are there any solutions that don't suffer the mentioned disadvantage?
Edit:
Both of current answers are elegant than my approaches (thank!), but still has disadvantage :-
- Oliv's requires #include "orange.h" in User.h.
- Richard Hodges's has virtual function calling.
In C++, collections are traversed using the iterator design pattern. The entire STL is designed around this concept. It may fit your needs:
You could define eatAll as a function that accept two iterators:
template<class Iterator,class Sentinel>
void eatAll(Iterator it, Sentinel s){
for (;it!=s;++it)
it->eaten();
}
Or the range like algorithm interface:
template<class Range>
void eatAll(Range& r){
for (auto& v:r)
v.eaten();
}
You will have to define you binary tree as a range (it must implement begin() and end()). Hopefully trees are kind of graph that can be linearised. All the smart work will then go in the iterator implementation!
If you want it truly polymorphic, then we have to deal with 2 things:
the actual type of the container
The fact that the result of dereferencing a map is a pair containing key and value references.
My view is that the answer to this is not to derive from containers, which is limiting, but to create a polymorphic "value iterator", which models all iterators and extracts their values correctly.
Then we can write code like this:
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}
To get this:
vector:
Orange
Orange
map:
Orange
Orange
Orange
Here's a minimal, complete implementation:
#include <typeinfo>
#include <memory>
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
// define an orange
struct Orange {
};
// a meta-function to get the type of the value of some iterated value_type
template<class ValueType> struct type_of_value
{
using type = ValueType;
};
// specialise it for maps and unordered maps
template<class K, class V> struct type_of_value<std::pair<K, V>>
{
using type = V;
};
template<class ValueType> using type_of_value_t = typename type_of_value<ValueType>::type;
// function to extract a value from an instance of a value_type
template<class ValueType> struct value_extractor
{
template<class V>
auto& operator()(V&& v) const {
return v;
}
};
// specialised for maps
template<class K, class V> struct value_extractor<std::pair<K, V>>
{
template<class Arg>
auto& operator()(Arg&& v) const {
return std::get<1>(v);
}
};
template<class Iter>
auto extract_value(Iter const& iter) -> auto&
{
using value_type = typename std::iterator_traits<Iter>::value_type;
auto e = value_extractor<value_type> {};
return e(*iter);
}
// a polymorphic (forward only at the moment) iterator
// which delivers the value (in the case of maps) or the element (every other container)
template<class ValueType>
struct PolymorphicValueIterator {
using value_type = type_of_value_t<ValueType>;
private:
struct iterator_details {
std::type_info const &type;
void *address;
};
struct concept {
virtual std::unique_ptr<concept> clone() const = 0;
virtual value_type& invoke_deref() const = 0;
virtual void invoke_next(std::size_t distance = 1) = 0;
virtual iterator_details get_details() = 0;
virtual bool is_equal(const iterator_details &other) const = 0;
virtual ~concept() = default;
};
template<class Iter>
struct model final : concept {
model(Iter iter)
: iter_(iter)
{}
std::unique_ptr<concept> clone() const override
{
return std::make_unique<model>(iter_);
}
virtual value_type& invoke_deref() const override {
return extract_value(iter_);
}
void invoke_next(std::size_t distance = 1) override
{
iter_ = std::next(iter_, distance);
}
iterator_details get_details() override {
return {
typeid(Iter),
std::addressof(iter_)
};
}
bool is_equal(const iterator_details &other) const override {
if (typeid(Iter) != other.type) {
return false;
}
auto pother = reinterpret_cast<Iter const*>(other.address);
Iter const& iother = *pother;
return iter_ == iother;
}
Iter iter_;
};
std::unique_ptr<concept> concept_ptr_;
public:
bool operator==(PolymorphicValueIterator const &r) const {
return concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
bool operator!=(PolymorphicValueIterator const &r) const {
return not concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
PolymorphicValueIterator &operator++() {
concept_ptr_->invoke_next(1);
return *this;
}
value_type& operator*() const {
return concept_ptr_->invoke_deref();
}
template<class Iter>
PolymorphicValueIterator(Iter iter)
{
concept_ptr_ = std::make_unique<model<Iter>>(iter);
}
PolymorphicValueIterator(PolymorphicValueIterator const& r)
: concept_ptr_(r.concept_ptr_->clone())
{}
PolymorphicValueIterator& operator=(PolymorphicValueIterator const& r)
{
concept_ptr_ = r.concept_ptr_->clone();
return *this;
}
};
template<class Iter>
auto makePolymorphicValueIterator(Iter iter)
{
using iter_value_type = typename std::iterator_traits<Iter>::value_type;
using value_type = type_of_value_t<iter_value_type>;
return PolymorphicValueIterator<value_type>(iter);
}
// a test
void do_orange_things(PolymorphicValueIterator<Orange> first, PolymorphicValueIterator<Orange> last)
{
while(first != last) {
std::cout << "Orange\n";
++first;
}
}
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}

Creating an STL container of `container< container<Base> >`

Is there a way to do
container< container<Base> >
When you have a bunch of container<Derived>s that you wish to keep together (to iterator over?)
A concrete example follows.
Say you have
struct Animal { } ;
struct Dog : public Animal { } ;
struct StripedDog : public Dog { } ;
struct Cat : public Animal { } ;
struct SpottedCat : public Cat { } ;
You wish to keep collections of Cats, SpottedCats, Dogs & StripedDogs, in vectors or lists naturally,
vector<Dog*> doggies ;
vector<StripedDog*> stripedDoggies ;
vector<Cat*> catties ;
vector<SpottedCat*> spottedCatties ;
You wish to iterate over ALL animals, however, so you wish to slam references to all dogs & cats collections into a single object,
vector< vector<Animal *>* > zoo ;
zoo.push_back( &doggies ) ;
zoo.push_back( &stripedDoggies ) ;
zoo.push_back( &catties ) ;
zoo.push_back( &spottedCatties ) ;
So now you can
feed( zoo ) ;
Of course, this doesn't compile. The vectors of cats & dogs are not vector<Animal*>, but rather vectors of their concrete types. Without retaining redundant lists and without losing the concrete type info (ie NOT using lists of base type Animal* as in vector<Animal*> stripedDoggies), is there a way to achieve equivalent behavior from C++?
I think you're looking at something like this, but not quite sure. Let me know if it isn't near to what you need and I'll drop it for favor of someone that does. The output demonstrates the virtual feed() operation does its business appropriately. Arranging a potential variadic parameter pack to that function would take me some time to cook on for awhile, and I'm not even sure it is possible.
But this should get you close.
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <vector>
// base. enforces inheritance by SFINAE
template<typename Base, typename T, template<typename, typename...> class V>
typename std::enable_if<std::is_base_of<Base, T>::value>::type
invoke(void (Base::*func)(), const class V<T*>& vec)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
for (auto p : vec)
(p->*func)();
}
// chain.
template<typename Base, typename T, template<typename, typename...> class V, typename... Args>
typename std::enable_if<std::is_base_of<Base, T>::value>::type
invoke(void (Base::*func)(), const class V<T*>& vec, Args... args)
{
invoke(func, vec);
invoke(func, args...);
}
int main()
{
struct Animal
{
virtual void feed()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
} ;
struct Dog : public Animal
{
void feed()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
} ;
struct StripedDog : public Dog {};
struct Cat : public Animal {};
struct SpottedCat : public Cat {};
std::vector<Dog*> doggies ;
std::vector<StripedDog*> stripedDoggies ;
std::vector<Cat*> catties ;
std::vector<SpottedCat*> spottedCatties ;
Dog dog;
doggies.push_back(&dog);
StripedDog sdog;
stripedDoggies.push_back(&sdog);
Cat cat;
catties.push_back(&cat);
invoke(&Animal::feed, doggies, stripedDoggies, catties, spottedCatties);
return 0;
}
Output
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = Dog, V = vector]
virtual void main()::Dog::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = StripedDog, V = vector]
virtual void main()::Dog::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = Cat, V = vector]
virtual void main()::Animal::feed()
typename std::enable_if<std::is_base_of<Base, T>::value>::type invoke(void (Base::*)(), const class V<T *> &) [Base = Animal, T = SpottedCat, V = vector]
Sorry about having to scroll to the right to see the types in that pretty-print, but they're pretty telling and should be looked at to see how this works. Note that both Dog and StripedDog containers properly fire the Dog::feed() member, while the Cat container properly fires the Animal::feed() base member since it provides no override.
Good luck, and I hope it helps.
Since you are using pointers, which are quite cheap to copy, you could probably do:
vector< Animal * > zoo;
zoo.append( zoo.end(), doggies.begin(), doggies.end() );
// ditto with the others
feed( zoo ); // just receives *one* vector with animals to feed
Another option if you don't want to copy/merge the vectors:
void feed() {}
template< typename V >
void feed( const V& v )
{
for( A* a : v )
{
// ...do something with 'a'
}
}
template< typename V, typename V2, typename... Vs >
void feed( const V& v, const V2& v2, const Vs&... vs )
{
feed( v );
feed( v2, vs... );
}
Now you can call feed( doggies, stripedDoggies, catties, spottedCatties );.
In general, if you are doing something like this, you would store them all in a single vector:
std::vector<std::shared_ptr<Animal>> animals;
If Animal defines a feed method, iterating over it simply means calling that function:
animals[i]->feed();
If you want to call specific functions based on types, you'll need to do some casting:
std::shared_ptr<Dog> pDog = std::dynamic_pointer_cast<Dog>(animals[i]);
std::shared_ptr<Cat> pCat = std::dynamic_pointer_cast<Cat>(animals[i]);
// other casts
if (pDog)
{
// do something with a dog
}
else if (pCat)
{
// do something with a cat
}
// etc
If you really wanted to store all of the animals in additional vectors, you can do that by wrapping the whole zoo:
class Zoo
{
private:
std::vector<std::shared_ptr<Animal>> animals;
std::vector<std::shared_ptr<Dog>> dogs;
// other vectors
public:
void AddDog(const Dog& d)
{
std::shared_ptr<Dog> pD = std::make_shared<Dog>(d);
dogs.push_back(pD);
std::shared_ptr<Animal> pA = std::static_pointer_cast<Animal>(pD);
animals.push_back(pA);
}
};
It doubles the number of pointers you are storing in memory, but pointers are fairly cheap. Then you can pass the whole zoo, or individual animal types without the need to do the casting every time.
Polymorphic iterators? shudder
Usage example:
#include <iostream>
struct Animal
{
virtual void print() = 0;
};
struct Elephant : Animal
{
virtual void print() override { std::cout << "toot"; }
};
struct Cat : Animal
{
virtual void print() override { std::cout << "meow"; }
};
struct Fox : Animal
{
virtual void print() override
{ std::cout << "ring-ding-ding-ding-dingeringeding"; }
};
#include <vector>
template<class T>
using simple_vector = std::vector<T>;
int main()
{
std::vector<Elephant> elephants(5);
std::vector<Cat> cats(3);
std::vector<Fox> foxes(1);
polymorphic_range_container<simple_vector, Animal> animals;
animals.push_back( std::make_pair(elephants.begin(), elephants.end()) );
animals.push_back( std::make_pair(cats.begin(), cats.end()) );
animals.push_back( std::make_pair(foxes.begin(), foxes.end()) );
for(auto& animal : animals)
{
animal.print(); std::cout << ", ";
}
std::cout << std::endl;
}
Implementation (basics):
#include <memory>
#include <algorithm>
#include <iterator>
#include <utility>
template<class T>
struct iterator_base
{
virtual void advance(int i) = 0;
virtual T& get() const = 0;
virtual bool equal(iterator_base const&) const = 0;
};
template<class ValueType, class Container, class Id>
struct polymorphic_iterator
{
polymorphic_iterator& operator++()
{
impl->advance(1);
if(container->is_end(*impl, id))
{
impl = container->next(id);
}
return *this;
}
ValueType& operator*() const { return impl->get(); }
friend bool operator==(polymorphic_iterator const& l,
polymorphic_iterator const& r)
{
if(l.impl == nullptr) return r.impl == nullptr;
if(r.impl == nullptr) return false;
return l.impl->equal( *(r.impl) );
}
friend bool operator!=(polymorphic_iterator const& l,
polymorphic_iterator const& r)
{
return not (l == r);
}
private:
std::unique_ptr< iterator_base<ValueType> > impl;
Container* container;
Id id;
friend Container;
polymorphic_iterator(Container* pc, Id pid, decltype(impl) p)
: impl( std::move(p) ), container(pc), id(std::move(pid))
{}
};
template<template<class> class Container, class Base>
class polymorphic_range_container
{
private:
using self = polymorphic_range_container;
struct IRange
{
using piterator = std::unique_ptr < iterator_base<Base> >;
virtual piterator begin() = 0;
virtual piterator end() = 0;
};
template<class It>
struct range : IRange
{
range(It p_begin, It p_end) : m_begin(p_begin), m_end(p_end) {}
using typename IRange::piterator;
piterator begin() override { return piterator{new iterator_impl(m_begin)}; }
piterator end() override { return piterator{new iterator_impl(m_end)}; }
private:
struct iterator_impl : iterator_base<Base>
{
iterator_impl(It p) : it(p) {}
virtual void advance(int i) override { std::advance(it, i); }
virtual Base& get() const override { return *it; }
virtual bool equal(iterator_base<Base> const& other) const override
{
iterator_impl const* pOther
= dynamic_cast<iterator_impl const*>(&other);
if(nullptr == pOther) return false;
else return it == pOther->it;
}
private:
It it;
};
iterator_impl m_begin;
iterator_impl m_end;
};
using container_type = Container< std::unique_ptr<IRange> >;
container_type ranges;
public:
template<class T>
void push_back(std::pair<T, T> p_range)
{
ranges.push_back( std::unique_ptr<IRange>{new range<T>(p_range.first, p_range.second)} );
}
using iterator = polymorphic_iterator<Base, self, typename container_type::const_iterator>;
iterator begin()
{
return iterator{this, ranges.cbegin(), ranges.front()->begin()};
}
iterator end()
{
return iterator{this, ranges.cend(), {nullptr}};
}
private:
friend iterator;
std::unique_ptr< iterator_base<Base> > next(typename container_type::const_iterator& p)
{
++p;
if(p == ranges.end()) return {nullptr};
else return (**p).begin();
}
bool is_end(iterator_base<Base> const& it, typename container_type::const_iterator const& id)
{
if(ranges.end() == id) return false;
else return (**id).end()->equal(it);
}
};

Traversing boost::month_iterators using ranges

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;
}

Faking a virtual templated function c++

I realize that virtual template functions are not allowed in c++. Because of my specific application domain, we deal with sets of algorithms (natural for implementation through polymorphism and inheritance) and need to enforce a common interface. Particular algorithmic classes work over iterators (not surprising), however we would like to fake virtualization through these templated functions. Here is an example of a solution we came up with using boost::mpl. I realize this is lengthy, but this is a minimal code example that I could create to simulate what I am aiming for. My specific question follows after the code.
#include <iostream>
#include <vector>
#include <boost/mpl/list.hpp>
#include <boost/mpl/for_each.hpp>
using namespace std;
class A;
class B;
class C;
typedef boost::mpl::list<B, C> DerivedClassList;
template<typename Base, typename Iterator>
struct VirtualFunc{
public:
VirtualFunc(Base* _memory, Iterator _begin, Iterator _end) :
m_memory(_memory), m_begin(_begin), m_end(_end){}
template<typename T>
void operator()(T& _t) {
T* tptr = dynamic_cast<T*>(m_memory);
if(tptr != NULL){
tptr->Print(m_begin, m_end);
}
}
private:
Base* m_memory;
Iterator m_begin, m_end;
};
class A{
public:
A(){}
virtual ~A(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
boost::mpl::for_each<DerivedClassList>(VirtualFunc<A, Iterator>(this, _begin, _end));
}
};
class B : public A {
public:
B(){}
virtual ~B(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
cout << "Begin::" << *_begin << endl;
}
};
class C : public A {
public:
C(){}
virtual ~C(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
for(Iterator it = _begin; it!=_end; it++)
cout << "Iterator::" << *it << endl;
}
};
int main(){
vector<size_t> numbers;
for(size_t i = 0; i<5; i++)
numbers.push_back(i);
A* printBegin = new B();
A* printAll = new C();
//faking virtualism will print just begin
printBegin->Print(numbers.begin(), numbers.end());
//faking virtualism will print all
printAll->Print(numbers.begin(), numbers.end());
}
So what is the pitfalls of this "fake virtual" templated functions? Is there a better more concise way to do this?
Also excuse the code standards, they are what we use at my workplace.
Why not replace with classic double dispatch pattern. It seems that you know your class hierarchy at the base level - so I would use the following. It is well known, Visitor or DoubleDispatch pattern and eliminate the non efficient dynamic_cast. Frankly - if I see dynamic_cast<> I always think about double-dispatch,
Known clasees:
class A;
class B;
class C;
Start point of virtual-ism:
class IVirtualFunc {
public:
virtual void callFor(B& memory) = 0;
virtual void callFor(C& memory) = 0;
};
Implementation for the template argument:
template<typename Iterator>
class VirtualFunc : public IVirtualFunc {
public:
VirtualFunc (Iterator _begin, Iterator _end) : begin(_begin), end(_end) {}
virtual void callFor(B& memory);
virtual void callFor(C& memory);
private:
Iterator begin;
Iterator end;
};
The abstract base class for the actual implementations:
class A{
public:
template<typename Iterator>
void Print(Iterator _begin, Iterator _end) {
VirtualFunc<Iterator> vFunc(_begin, _end);
dispatch(vFunc);
}
virtual void dispatch(IVirtualFunc&) = 0;
};
First actual implementation with double dispatch for it (VirtualFunc<Iterator>::callFor(B& b)):
class B : public A {
public:
B(){}
virtual ~B(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
cout << "Begin::" << *_begin << endl;
}
virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); }
};
template<typename Iterator>
void VirtualFunc<Iterator>::callFor(B& b)
{
b.Print(begin, end);
}
Second actual implementation with double dispatch for it (VirtualFunc<Iterator>::callFor(C& c)):
class C : public A {
public:
C(){}
virtual ~C(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
for(Iterator it = _begin; it!=_end; it++)
cout << "Iterator::" << *it << endl;
}
virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); }
};
template<typename Iterator>
void VirtualFunc<Iterator>::callFor(C& c)
{
c.Print(begin, end);
}
And the proof it works:
int main(){
vector<size_t> numbers;
for(size_t i = 0; i<5; i++)
numbers.push_back(i);
A* printBegin = new B();
A* printAll = new C();
//faking virtualism will print just begin
printBegin->Print(numbers.begin(), numbers.end());
//faking virtualism will print all
printAll->Print(numbers.begin(), numbers.end());
}
OUTPUT:
Begin::0
Iterator::0
Iterator::1
Iterator::2
Iterator::3
Iterator::4