Boost.Iterator Facade with an incomplete Value argument - c++

I'm trying to use boost::iterator_facade with an incomplete Value
template argument. This fails, because iterator_facade is trying to
check if the type is_pod.
Is this the expected behavior? Can I work around this limitation in
some way? I could write a class template that simply proxies foo and
provides implicit conversion to it, but I'd rather have a simpler
solution.
#include <boost/iterator/iterator_facade.hpp>
class iter
: public boost::iterator_facade< iter,
iter,
boost::forward_traversal_tag
>
{
private:
friend class boost::iterator_core_access;
void increment() { }
bool equal(iter const& other) const { return true; }
iter& dereference() const { return const_cast<iter&>(static_cast<const iter&>(*this)); }
};
int main()
{
iter f;
return 0;
}

If is_pod a problem can't you just specialize it with iter type?
On ideone - http://ideone.com/1DR8v - it seems to be working that way, even if type in not defined at all and is_pod is specialized with that incomplete type.

Related

Why are insert iterators not copyable?

The classes std::back_insert_iterator, std::front_insert_iterator and std::insert_iterator cannot be copied. Both the assignment operator and the constructor do not allow copies. Also the properties container (and iter in std::insert_iterator) are protected.
I wonder why. I'd like to copy these into a lambda function to use later to populate the containers.
Something like this doesn't seem possible:
template<class OutIter>
std::function<void()>
generateFunction(OutIter out_iter) {
return
[out_iter] // not possible and a reference becomes dangling
() {
// write to outpit iterator.
}
}
I'm just wondering why? It would be handy to be able to use the iterators here. Now I either have to build my own inserter or work directly on the containers.
Or does anyone have another idea?
Edit:
It seems to be copyable. But if i use it as a lambda capture, i got a const version of the inserter.
This code does not compile:
#include <functional>
#include <vector>
#include <iterator>
template<class OutIter>
inline std::function<void(int)>
generateFunction(OutIter out_iter) {
return
[out_iter] (int value) {
*out_iter = value;
++out_iter;
};
}
int main() {
std::vector<int> v;
auto myFn = generateFunction(std::back_inserter(v));
myFn(1);
myFn(2);
}
Error is:
<source>:10:13: error: passing 'const std::back_insert_iterator<std::vector<int> >' as 'this' argument discards qualifiers [-fpermissive]
10 | *out_iter = value;
Solution: The Lambda has to be mutable:
template<class OutIter>
inline std::function<void(int)>
generateFunction(OutIter out_iter) {
return
[out_iter] (int value) mutable {
*out_iter = value;
++out_iter;
};
}
Many thanks for the helpful answers.
The classes std::back_insert_iterator, std::front_insert_iterator and std::insert_iterator cannot be copied. Both the assignment operator and the constructor do not allow copies.
Your assumption is wrong. All of the iterators mentioned must satisfy the LegacyOutputIterator named requirement which implies that they also satisfy the LegacyIterator named requirement which requires the iterator to be copyable
Gcc, clang and MSVC all consider the iterators to be copyable, see godbolt.
template <class Container>
class insert_iterator :
public iterator<output_iterator_tag,void,void,void,void>
{
protected:
Container* container;
typename Container::iterator iter;
public:
typedef Container container_type;
explicit insert_iterator (Container& x, typename Container::iterator i)
: container(&x), iter(i) {}
insert_iterator<Container>& operator= (typename Container::const_reference value)
{ iter=container->insert(iter,value); ++iter; return *this; }
insert_iterator<Container>& operator* ()
{ return *this; }
insert_iterator<Container>& operator++ ()
{ return *this; }
insert_iterator<Container>& operator++ (int)
{ return *this; }
};

Do custom iterators always need to explicitly specify value_type?

Since iterator is deprecated, I began converting iterators in my code base to use non-deprecated constructs. I could not seem to make my indirect iterator compliant with the std::forward_iterator concept unless I explicitly specified value_type. I would like to know if this is expected.
Based on the definition of iter_value_t and indirectly_readible_traits, it seems like there is no automatic inference of std::iter_value_t. Naively, I would have expected std::iter_value_t<Itr> to be defined as std::remove_cvref_t<std::iter_reference_t<Itr>> if no definition for value_type is present (which is checked via has-member-value-type in indirectly_readible_traits).
#include <vector>
template <std::forward_iterator Itr>
class IndirectItr {
public:
using value_type = std::iter_value_t<Itr>; // **do I need this?**
explicit IndirectItr(Itr itr = {}) : m_itr{itr} {}
bool operator==(const IndirectItr& rhs) const { return m_itr == rhs.m_itr; }
bool operator!=(const IndirectItr& rhs) const { return m_itr != rhs.m_itr; }
typename std::iter_reference_t<Itr> operator *() const { return *m_itr; }
IndirectItr& operator++() { ++m_itr; return *this; }
IndirectItr operator++(int) { auto ret = *this; ++(*this); return ret; }
typename std::iter_difference_t<Itr> operator-(const IndirectItr& rhs) const { return m_itr - rhs.m_itr; }
private:
Itr m_itr;
};
using Base = std::vector<int>::iterator;
static_assert(std::forward_iterator<IndirectItr<Base>>);
static_assert(std::same_as<std::iter_value_t<Base>, std::remove_cvref_t<std::iter_reference_t<Base>>>);
P.S. I have several indirect iterator definitions that wrap other iterators. The example above is representative of a custom indirect iterator. I don't have this exact class in my code.
You don't have to have a member value_type on your iterator. But your only alternative is to specialize iterator_traits<T> for your iterator type and provide a value_type alias there. So you may as well make it a member of the iterator.
The value_type cannot be computed from something else, as it may have no obvious relation to reference or any other operation on the iterator. This is one of the things that allows for proxy iterators, which pre-C++20 concepts did not.
std::forward_iterator includes std::input_iterator, which includes std::indirectly_readable, which contains:
requires(const In in) {
typename std::iter_value_t<In>;
typename std::iter_reference_t<In>;
typename std::iter_rvalue_reference_t<In>;
{ *in } -> std::same_as<std::iter_reference_t<In>>;
{ ranges::iter_move(in) } -> std::same_as<std::iter_rvalue_reference_t<In>>;
}
(where In is std::remove_cvref_t<IndirectItr<Base>>).
That typename std::iter_value_t<In>; line requires you to declare a value_type or to specialize std::iterator_traits<IndirectItr<Base>> (and provide value_type there), as explained here.
You cannot specialize std::iterator_traits<IndirectItr<T>> for all T (see also), so you can either pick the first and very reasonable option, or fully specialize for each IndirectItr you intend to use.

implementing a static polymorphic iterator

I am trying to implement an iterator interface for a templated type hierarchy that uses static polymorphism to avoid overhead associated with solutions that forward to an implementation (unless it can be compiled away).
I've included a short demonstration of the types and interfaces I'm building, and inline comments referencing where I am getting stuck.
The top of the hierarchy shown directly below is a generic Box<T>. The Convert method may return a new Box<U> by applying a function U Func(Box<T>) function to each element.
template<typename T>
class Box : public std::enable_shared_from_this<Box<T>> {
public:
template <typename Func>
auto Convert(Func f) -> std::shared_ptr<Box<decltype(f(std::declval<T>()))>>;
// This is what I am trying to achieve using a statically
// compiled solution (e.g. without the use of a subclass
// returning an implementation pointer and using pimpl).
//
// const_iterator cbegin();
// const_iterator cend();
// Uses the sub-class cbegin/cend interface
std::vector<T> elements() {
std::vector<T> result;
std::copy(cbegin(), cend(), std::back_inserter(result);
return result;
}
};
And here is a ConvertedBox<T> that stores a pointer to a Box and a conversion function. Here the iterator is a wrapper around the referenced variable rdd_ that that applies func_ each time the iterator is dereferenced.
template<typename T, typename U, typename Func>
class ConvertedBox : public Box<T> {
public:
ConvertedBox(typename std::shared_ptr<Box<U>> box, Func func) :
box_(box), func_(func)
{}
// Return iterator wrapper around box_->cbegin()
//const_iterator cbegin()
//const_iterator cend()
private:
std::shared_ptr<Box<U>> box_;
Func func_;
};
And finally we provide a source box that wraps a concrete vector (other sources are used in practice).
template<typename T>
class VectorBox : public Box<T> {
public:
ConvertedBox(const std::vector<T>& data) : data_(data)
{}
// Return iterator wrapper std::vector<T>::const_iterator
//const_iterator cbegin() {
// return data_.cbegin();
//}
//const_iterator cend() { ... }
private:
const typename std::vector<T>& data_;
};
I've tried all sorts of CRTP tricks involving std::iterator and cannot seem to put the pieces together for this. I would like to avoid anything that relies on boost, but assume anything in C++11 in OK.
Note that I am only having problems figuring out this iterator situation (the rest of the parts I've included are just for context).

How to write a simple, type-erased composable iterator in C++11

I'm trying to write a simple composable Iterator that does not expose the internal type (so I can use one of these iterators in the interface and can realize different operations like concat, filter, ...). It's really intended to be simple but I'm currently stumbling over a simple compile error which I can't resolve
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <functional>
#include <vector>
template <typename T>
struct RangeIteratorData
{
std::function<T&()> dereference;
std::function<void()> increment;
};
template <typename T>
class RangeIterator
{
public:
template <typename I>
RangeIterator(I& iter)
{
auto dereference = [iter]() { return *iter; };
auto increment = [iter]() -> void { ++iter; }; //here's the error
m_data.dereference = dereference;
m_data.increment = increment;
}
T& operator*();
RangeIterator<T>& operator++();
private:
RangeIteratorData<T> m_data;
};
template <typename T>
RangeIterator<T>& RangeIterator<T>::operator++()
{
m_data.increment();
return *this;
}
template <typename T>
T& RangeIterator<T>::operator*()
{
return m_data.dereference();;
}
TEST_CASE("Wrap existing iterator in range iterator")
{
std::vector<int> container{ 1,2,3 };
RangeIterator<int> begin = RangeIterator<int>(container.begin());
++begin;
REQUIRE(*begin == 1);
}
The error message is:
Error C2678 binary '++': no operator found which takes a left-hand operand of type 'const std::_Vector_iterator>>' (or there is no acceptable conversion)
I'm using VS2015. The code itself is far from complete but I don't get the meaning of this error message. I especially don't understand where the const comes from.
It would be nice if someone could point me in the correct location.
auto increment = [iter]() -> void { ++iter; };
Change this line to:
auto increment = [iter]() mutable -> void { ++iter; };
Without the mutable, the operator() member function of the lambda's type is const, so it can't modify the iterator.

Using boost counting_iterator with Incrementable type

I'm trying to use an Incrementable type with a boost::counting_iterator.
The boost::counting_iterator documentation says that the iterator works for Incrementable types, i.e. types that are CopyConstructible, Assignable, PreIncrementable, and EqualityComparable.
My Incrementable type:
template<class T> struct Incrementable {
// CopyConstructible:
Incrementable() : value(0) {}
Incrementable(const Incrementable& other) : value(other.value) {}
explicit Incrementable(const T& other) : value(other) {}
// Assignable:
inline Incrementable& operator=(const Incrementable& other) {
value = other.value;
return *this;
}
// PreIncrementable:
inline Incrementable& operator++() {
++value;
return *this;
}
// EqualityComparable:
friend
inline bool operator==(const Incrementable& a, const Incrementable& b) {
return a.value == b.value;
}
T value;
};
This fails to compile:
#include <boost/iterator/counting_iterator.hpp>
#include "incrementable.h"
int main() {
boost::counting_iterator<Incrementable<int>> a(Incrementable<int>(0));
return 0;
}
The error:
usr/local/include/boost/iterator/iterator_categories.hpp:161:60: error: no type named 'iterator_category' in 'boost::detail::iterator_traits<Incrementable<int> >'
typename boost::detail::iterator_traits<Iterator>::iterator_category
I'd guess that I need to implement an iterator_category either for:
a counting_iterator of my Incrementable type,
or as the error says, for my Incrementable type (does this even make sense? my Incrementable type is not an iterator).
Neither is clear from the documentation (which omits this topic completely), and I fail to find any information about it in the other parts of the library.
So I added the following to boost::detail namespace:
namespace boost { namespace detail {
template <class T> struct is_numeric<Incrementable<T>>
: mpl::true_ {};
}} // boost::detail namespace
and now everything compiles and works as expected. Still, I really doubt that the library was intended to be used this way.
Anyone knows the proper/clean way to implement this?
Steve Jessop's suggestion: specializing std::numeric_limits also works:
namespace std {
template<class T>
class numeric_limits<Incrementable<T>> : public numeric_limits<T> {
public:
static const bool is_specialized = true;
};
}
Still I don't know if this is the right thing to do for an incrementable type.
I'm not sure whether Boost defines "incrementable type" as you say. If it does define it as you say, then there's a documentation bug, it shouldn't say that counting_iterator works for "any incrementable type", because those aren't the whole requirements. Or I suppose it's true if "provided that you specify the other template parameters correctly" goes without saying.
The requirements on the Incrementable template parameter for counting_iterator are given in the document you link to (starting from "iterator_category is defined as follows...", because the actual requirements section refers back to iterator_category).
You should not specialize boost::detail::is_numeric. You should specialize std::numeric_limits. But in your example, I think you've actually narrowed the interface of T too much to claim that your type is numeric (it doesn't have arithmetic). If your type is neither numeric nor an iterator, I think you're supposed to specify CategoryOrTraversal as forward_iterator_tag. I may have missed something.