[type_erasure] Problem with iterators
, double>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Map = boost::mpl::map1<boost::mpl::pair<boost::type_erasure::_self, __gnu_cxx::__normal_iterator<const double*, std::vector<double> > > ]’ /home/sguazt/sys/src/git/boost/boost/type_erasure/any.hpp:225:13: required from ‘boost::type_erasure::any<Concept, T>::any(U&&) [with U = __gnu_cxx::__normal_iterator<const double*, std::vector<double> >&; Concept = boost::mpl::vector<boost::type_erasure::forward_iterator<>, boost::type_erasure::same_type<boost::type_erasure::deduced<boost::type_erasure::iterator_value_type<boost::type_erasure::_self> , double>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; T = boost::type_erasure::_self]’ erasure.cpp:36:40: required from ‘std::vector<_RealType>
Hi, I'm new to the Type Erasure library. I need to write a base class with type-erased forward iterators. To do so I've taken inspiration from the print_sequence.cpp example I've found in the Type Erasure source tree. At the end of the email there is the whole code of my tentative, called "erasure.cpp". Unfortunately, I've problems (presumably) with const iterators which cause the following compile error: $ g++ -Wall -Wextra -pedantic -std=c++11 -I$HOME/sys/src/git/boost -o erasure erasure.cpp -lm *** [begin error] *** In file included from /home/sguazt/sys/src/git/boost/boost/type_erasure/iterator.hpp:20:0, from erasure.cpp:2: /home/sguazt/sys/src/git/boost/boost/type_erasure/operators.hpp: In instantiation of ‘static R boost::type_erasure::dereferenceable<R, T>::apply(const T&) [with R = double&; T = __gnu_cxx::__normal_iterator<const double*, std::vector<double> >]’: /home/sguazt/sys/src/git/boost/boost/type_erasure/detail/instantiate.hpp:91:9: required from ‘static void boost::type_erasure::detail::instantiate_concept7::apply(Concept*, Map*) [with Concept = boost::mpl::vector<boost::type_erasure::forward_iterator<>, boost::type_erasure::same_type<boost::type_erasure::deduced<boost::type_erasure::iterator_value_type<boost::type_erasure::_self> base<T>::foo(IterT, IterT) [with IterT = __gnu_cxx::__normal_iterator<const double*, std::vector<double> >; T = double]’ erasure.cpp:77:73: required from here /home/sguazt/sys/src/git/boost/boost/type_erasure/operators.hpp:134:44: error: invalid initialization of reference of type ‘double&’ from expression of type ‘const double’ static R apply(const T& arg) { return *arg; } *** [/end error] *** The GCC version is 4.9.2. Here below is the content of "erasure.cpp". If I comment lines below the comment "THE FOLLOWING WON'T COMPILE" I get no error. So the problem is due to the use of cbegin/cend. *** [erasure.cpp] *** #include <boost/type_erasure/any.hpp> #include <boost/type_erasure/iterator.hpp> #include <boost/type_erasure/operators.hpp> #include <boost/type_erasure/same_type.hpp> #include <boost/mpl/vector.hpp> #include <boost/smart_ptr.hpp> #include <cmath> #include <cstddef> #include <iostream> #include <iterator> #include <vector> namespace mpl = boost::mpl; namespace te = boost::type_erasure; template <typename T> using fwd_iter_impl_t = te::any< mpl::vector< te::forward_iterator<>, te::same_type<te::forward_iterator<>::value_type,T>>>; template <typename T> class base { protected: typedef fwd_iter_impl_t<T> fwd_iter_type; public: virtual ~base() { } template <typename IterT> std::vector<T> foo(IterT first, IterT last) { return this->do_foo(first, last); } private: virtual std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) = 0; }; // base template <typename T> class derived: public base<T> { private: typedef typename base<T>::fwd_iter_type fwd_iter_type; std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) { const std::ptrdiff_t n = std::distance(first, last); std::vector<T> res(n); for (std::size_t i = 0; first != last; ++first, ++i) { res[i] = std::pow(*first,i)/n; } return res; } }; // derived int main() { std::vector<double> dv; dv.push_back(5); dv.push_back(8); dv.push_back(11); boost::scoped_ptr< base<double> > p_base(new derived<double>()); // begin/end const std::vector<double> foos = p_base->foo(dv.begin(), dv.end()); for (std::size_t i = 0; i < foos.size(); ++i) { std::cout << "foos[" << i << "]: " << foos[i] << std::endl; } //--- THE FOLLOWING WON'T COMPILE // cbegin/cend const std::vector<double> cfoos = p_base->foo(dv.cbegin(), dv.cend()); for (std::size_t i = 0; i < cfoos.size(); ++i) { std::cout << "cfoos[" << i << "]: " << cfoos[i] << std::endl; } } *** [/erasure.cpp] *** Thank you very much for your help. Best, -- Marco
-----Original Message----- From: Boost-users [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Marco Guazzone Sent: 24 January 2015 07:57 To: boost-users@lists.boost.org Subject: [Boost-users] [type_erasure] Problem with iterators
Hi,
I'm new to the Type Erasure library.
I need to write a base class with type-erased forward iterators. To do so I've taken inspiration from the print_sequence.cpp example I've found in the Type Erasure source tree. At the end of the email there is the whole code of my tentative, called "erasure.cpp".
Unfortunately, I've problems (presumably) with const iterators which cause the following compile error:
<big snip> I've tried to compile your code using VS 12.0.30110.00 Update 1 but it won't even take the non-const iterator. (It fails missing a type in constructible.hpp) With this compiler version, I have used Steven's print sequence examples and some derived versions (all non- const values I think) previously but I now find that none of the previously run example compile, failing like this I:\modular-boost\boost/type_erasure/constructible.hpp(88): error C2061: syntax error : identifier 'type' ... for reasons that I have yet to fathom. Does some change now *require* variadics so I need a more recent compiler? (I wouldn't dare look at the underlying code, (though it smells of a const iterator version not being defined?) - that requires a brain the size of a planet ;-) However this test passes (along with all the other tests), whatever that might mean https://github.com/boostorg/type_erasure/blob/develop/test/test_construct_cr... and Steven Watanabe seems to unavailable by email :-(( So that is no help at all for you :-( Sorry. Paul --- Paul A. Bristow Prizet Farmhouse Kendal UK LA8 8AB +44 (0) 1539 561830
AMDG On 01/24/2015 12:56 AM, Marco Guazzone wrote:
I need to write a base class with type-erased forward iterators. To do so I've taken inspiration from the print_sequence.cpp example I've found in the Type Erasure source tree. At the end of the email there is the whole code of my tentative, called "erasure.cpp".
Unfortunately, I've problems (presumably) with const iterators which cause the following compile error:
Iterators are mutable by default. If you want a const iterator, you need to specify the reference type. (If you look at the range print example, it uses forward_iterator<_iter, const _t&>)
$ g++ -Wall -Wextra -pedantic -std=c++11 -I$HOME/sys/src/git/boost -o erasure erasure.cpp -lm
*** [begin error] *** <snip> erasure.cpp:77:73: required from here /home/sguazt/sys/src/git/boost/boost/type_erasure/operators.hpp:134:44: error: invalid initialization of reference of type ‘double&’ from expression of type ‘const double’ static R apply(const T& arg) { return *arg; }
*** [/end error] ***
The GCC version is 4.9.2.
Here below is the content of "erasure.cpp". If I comment lines below the comment "THE FOLLOWING WON'T COMPILE" I get no error. So the problem is due to the use of cbegin/cend.
In Christ, Steven Watanabe
On Sat, Jan 24, 2015 at 9:29 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 01/24/2015 12:56 AM, Marco Guazzone wrote:
I need to write a base class with type-erased forward iterators. To do so I've taken inspiration from the print_sequence.cpp example I've found in the Type Erasure source tree. At the end of the email there is the whole code of my tentative, called "erasure.cpp".
Unfortunately, I've problems (presumably) with const iterators which cause the following compile error:
Iterators are mutable by default. If you want a const iterator, you need to specify the reference type. (If you look at the range print example, it uses forward_iterator<_iter, const _t&>)
[big cut] Hi Steven, Probably I haven't correctly understand your suggestion since now that I've commented the definition of "fwd_iter_impl_t" and replaced the "typedef" definition in "base" class with the following one: struct _t: te::precision { }; struct _iter: te::precision { }; //... typedef te::any< mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type>>, _iter> fwd_iter_type; I get an error when calling the std::pow function: erasure.cpp: In instantiation of ‘std::vector<_RealType> derived<T>::do_foo(derived<T>::fwd_iter_type, derived<T>::fwd_iter_type) [with T = double; derived<T>::fwd_iter_type = boost::type_erasure::any<boost::mpl::vector<boost::type_erasure::forward_iterator<_iter, const _t&>, boost::type_erasure::same_type<_t, boost::type_erasure::deduced<boost::type_erasure::iterator_value_type<_iter>
, _iter>]’: erasure.cpp:79:1: required from here erasure.cpp:51:39: error: no matching function for call to ‘pow(boost::type_erasure::rebind_any<boost::type_erasure::concept_interface<boost::type_erasure::assignable<_iter, _iter>, boost::type_erasure::concept_interface<boost::type_erasure::incrementable<_iter>, boost::type_erasure::concept_interface<boost::type_erasure::same_type<_t, _t>, boost::type_erasure::any_base<boost::type_erasure::any<boost::mpl::vector<boost::type_erasure::forward_iterator<_iter, const _t&>, boost::type_erasure::same_type<_t, boost::type_erasure::deduced<boost::type_erasure::iterator_value_type<_iter> , _iter> >, _iter, void>, _iter, void>, _iter, void>, const _t&>::type, std::size_t&)’ res[i] = std::pow(*first,i)/n;
(The error message continues by listing possible candidates) Here below is the new code: *** [erasure.cpp] *** #include <boost/type_erasure/any.hpp> #include <boost/type_erasure/iterator.hpp> #include <boost/type_erasure/operators.hpp> #include <boost/type_erasure/same_type.hpp> #include <boost/mpl/vector.hpp> #include <boost/smart_ptr.hpp> #include <cmath> #include <cstddef> #include <iostream> #include <iterator> #include <vector> namespace mpl = boost::mpl; namespace te = boost::type_erasure; struct _t: te::placeholder { }; struct _iter: te::placeholder { }; template <typename T> class base { protected: typedef te::any< mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type>>, _iter> fwd_iter_type; public: virtual ~base() { } template <typename IterT> std::vector<T> foo(IterT first, IterT last) const { return this->do_foo(first, last); } private: virtual std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) const = 0; }; // base template <typename T> class derived: public base<T> { private: typedef typename base<T>::fwd_iter_type fwd_iter_type; std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) const { const std::ptrdiff_t n = std::distance(first, last); std::vector<T> res(n); for (std::size_t i = 0; first != last; ++first, ++i) { res[i] = std::pow(*first,i)/n; } return res; } }; // derived int main() { std::vector<double> dv; dv.push_back(5); dv.push_back(8); dv.push_back(11); boost::scoped_ptr< base<double> > p_base(new derived<double>()); // begin/end const std::vector<double> foos = p_base->foo(dv.begin(), dv.end()); for (std::size_t i = 0; i < foos.size(); ++i) { std::cout << "foos[" << i << "]: " << foos[i] << std::endl; } //--- THE FOLLOWING WON'T COMPILE // cbegin/cend const std::vector<double> cfoos = p_base->foo(dv.cbegin(), dv.cend()); for (std::size_t i = 0; i < cfoos.size(); ++i) { std::cout << "cfoos[" << i << "]: " << cfoos[i] << std::endl; } } *** [/erasure.cpp] *** Where am I wrong? Thank you for your time. -- Marco
AMDG On 01/24/2015 03:10 PM, Marco Guazzone wrote:
Probably I haven't correctly understand your suggestion since now that I've commented the definition of "fwd_iter_impl_t" and replaced the "typedef" definition in "base" class with the following one:
struct _t: te::precision { }; struct _iter: te::precision { }; //... typedef te::any< mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type>>, _iter> fwd_iter_type;
You still need same_type<_t, T>. (Yes, I realize the interface for forward_iterator isn't the best. same_type<_t, xxx::value_type> shouldn't be necessary, at the very least.) In Christ, Steven Watanabe
On Sun, Jan 25, 2015 at 7:43 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 01/24/2015 03:10 PM, Marco Guazzone wrote:
Probably I haven't correctly understand your suggestion since now that I've commented the definition of "fwd_iter_impl_t" and replaced the "typedef" definition in "base" class with the following one:
struct _t: te::precision { }; struct _iter: te::precision { }; //... typedef te::any< mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type>>, _iter> fwd_iter_type;
You still need same_type<_t, T>. (Yes, I realize the interface for forward_iterator isn't the best. same_type<_t, xxx::value_type> shouldn't be necessary, at the very least.)
So, there is no way to make it work, is it? I've tried many combinations of params, but none of them seems to work. If someone ends up with a working solution, I would be very grateful if (s)he shares it with us :) Cheers, -- Marco
AMDG On 01/25/2015 03:24 PM, Marco Guazzone wrote:
On Sun, Jan 25, 2015 at 7:43 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
You still need same_type<_t, T>. (Yes, I realize the interface for forward_iterator isn't the best. same_type<_t, xxx::value_type> shouldn't be necessary, at the very least.)
So, there is no way to make it work, is it?
I've tried many combinations of params, but none of them seems to work.
If someone ends up with a working solution, I would be very grateful if (s)he shares it with us :)
I think you need two uses of same_type to make it work. _t, T, and ...::value_type all need to be the same. If all else fails, the iterator concepts are just composed of a bunch of operators with a specialization of concept_interface for the iterator_traits typedefs. In Christ, Steven Watanabe
On Wed, Jan 28, 2015 at 10:21 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 01/25/2015 03:24 PM, Marco Guazzone wrote:
On Sun, Jan 25, 2015 at 7:43 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
You still need same_type<_t, T>. (Yes, I realize the interface for forward_iterator isn't the best. same_type<_t, xxx::value_type> shouldn't be necessary, at the very least.)
So, there is no way to make it work, is it?
I've tried many combinations of params, but none of them seems to work.
If someone ends up with a working solution, I would be very grateful if (s)he shares it with us :)
I think you need two uses of same_type to make it work. _t, T, and ...::value_type all need to be the same. If all else fails, the iterator concepts are just composed of a bunch of operators with a specialization of concept_interface for the iterator_traits typedefs.
Hi Steven, Do you mean this? typedef mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, T>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type> > requirements; typedef te::any< requirements, _iter> fwd_iter_type; If you do, I've tried but it doesn't work :( The entire code is here below. If you don't, could you please write in C++ your idea? *** [erasure.cpp] *** #include <boost/type_erasure/any.hpp> #include <boost/type_erasure/iterator.hpp> #include <boost/type_erasure/operators.hpp> #include <boost/type_erasure/same_type.hpp> #include <boost/type_erasure/tuple.hpp> #include <boost/mpl/vector.hpp> #include <boost/smart_ptr.hpp> #include <cmath> #include <cstddef> #include <iostream> #include <iterator> #include <vector> namespace mpl = boost::mpl; namespace te = boost::type_erasure; struct _t: te::placeholder { }; struct _iter: te::placeholder { }; template <typename T> class base { protected: typedef mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, T>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type> > requirements; typedef te::any< requirements, _iter> fwd_iter_type; public: virtual ~base() { } template <typename IterT> std::vector<T> foo(IterT first, IterT last) const { return this->do_foo(first, last); } private: virtual std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) const = 0; }; // base template <typename T> class derived: public base<T> { private: typedef typename base<T>::fwd_iter_type fwd_iter_type; std::vector<T> do_foo(fwd_iter_type first, fwd_iter_type last) const { const std::ptrdiff_t n = std::distance(first, last); std::vector<T> res(n); for (std::size_t i = 0; first != last; ++first, ++i) { //res[i] = std::pow(static_cast<T>(*first),i)/n; res[i] = std::pow(*first,i)/n; } return res; } }; // derived int main() { std::vector<double> dv; dv.push_back(5); dv.push_back(8); dv.push_back(11); boost::scoped_ptr< base<double> > p_base(new derived<double>()); // begin/end const std::vector<double> foos = p_base->foo(dv.begin(), dv.end()); for (std::size_t i = 0; i < foos.size(); ++i) { std::cout << "foos[" << i << "]: " << foos[i] << std::endl; } // cbegin/cend const std::vector<double> cfoos = p_base->foo(dv.cbegin(), dv.cend()); for (std::size_t i = 0; i < cfoos.size(); ++i) { std::cout << "cfoos[" << i << "]: " << cfoos[i] << std::endl; } } *** [/erasure.cpp] *** Thank you very much. -- Marco
AMDG On 01/30/2015 03:38 AM, Marco Guazzone wrote:
Do you mean this?
typedef mpl::vector< te::forward_iterator<_iter, const _t&>, te::same_type<_t, T>, te::same_type<_t, te::forward_iterator<_iter, const _t&>::value_type> > requirements; typedef te::any< requirements, _iter> fwd_iter_type;
If you do, I've tried but it doesn't work :( The entire code is here below. If you don't, could you please write in C++ your idea?
Yes, that's what I meant. The fact that it doesn't work is a bug. You can try using forward_iterator<_iter, const double&>. It isn't quite right because fwd_iter_type::value_type will be wrong, though. Hmmm. Try this: forward_iterator<_iter, const double&, std::ptrdiff_t, double> In Christ, Steven Watanabe
On Fri, Jan 30, 2015 at 5:43 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
Yes, that's what I meant. The fact that it doesn't work is a bug. You can try using forward_iterator<_iter, const double&>. It isn't quite right because fwd_iter_type::value_type will be wrong, though. Hmmm. Try this: forward_iterator<_iter, const double&, std::ptrdiff_t, double>
Steven, I really thank you. It works! Just for anyone interested on this, here is the working solution (I just put the important changes; the rest of the code is the same as before): typedef mpl::vector< te::forward_iterator<_iter, const T&, std::ptrdiff_t, T> > requirements; typedef te::any< requirements, _iter> fwd_iter_type; Best, -- Marco
participants (3)
-
Marco Guazzone
-
Paul A. Bristow
-
Steven Watanabe