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; }
};
Related
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.
The title of this question used to be: Are there practical advantages to creating an iterator class compared to returning raw pointers from begin and end functions?
Recently I have been working on a code base which uses MFC and objects such as CArray<T, U>.
Some parts of new code which has been written make use of the STL and <algorithm> library.
For example
CArray<int int> carray;
carray // do stuff
std::vector<int> stlvector(begin(carray), end(carray));
stlvector.dostuff() // do stuff
I recently asked a question about creating iterators for a class such as CArray, which I do not have access to.
I now have some further questions about this. The first question can be found here. Here is my second question:
Should the begin and end functions return raw pointers or iterators?
In the linked question above, an example was provided as an answer which returns raw pointers. This answer was very similar to the implementation I used.
template<typename T, typename U>
auto begin(const CArray<T, U> &array>)
{
return &array[0];
}
template<typename T, typename U>
auto end(const CArray<T, U> &array>)
{
return (&array[array.GetCount() - 1]) + 1;
}
These functions return raw pointers. However I attempted to implement an iterator solution. So far I have not been successful.
The main reference which I used during my research can be found here:
https://internalpointers.com/post/writing-custom-iterators-modern-cpp
First attempt
This is the first attempt that I made in finding a solution.
You can play with this code here.
#include <iostream>
#include <iterator>
#include <algorithm>
template <typename U>
class CArrayForwardIt
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = U;
using pointer = U*;
using reference = U&;
public:
CArrayForwardIt(pointer ptr)
: m_ptr(ptr)
{
}
// = default?
//CArrayForwardIt(CArrayForwardIt<U> other)
// : m_ptr(ptr)
// {
// }
reference operator*() const
{
return *m_ptr;
}
// what does this do, don't understand why operator-> is needed
// or why it returns a U* type
pointer operator->()
{
return m_ptr;
}
CArrayForwardIt& operator++()
{
++ m_ptr;
return *this;
}
CArrayForwardIt operator++(int)
{
CArrayForwardIt tmp(*this);
++ (*this);
return tmp;
}
friend bool operator==(const CArrayForwardIt& lhs, const CArrayForwardIt& rhs)
{
return lhs.m_ptr == rhs.m_ptr;
}
friend bool operator!=(const CArrayForwardIt& lhs, const CArrayForwardIt& rhs)
{
return !(lhs == rhs);
}
private:
pointer m_ptr;
};
template<typename T, typename U>
auto begin(const CArray<T, U> &array)
{
return CArrayForwardIt<U>(&array[0]);
}
template<typename T, typename U>
auto end(const CArray<T, U> &array)
{
return CArrayForwardIt<U>((&array[array.GetCount() - 1]) + 1);
}
int main()
{
CArray<int, int> c;
// do something to c
std::vector<int> v(begin(c), end(c));
return 0;
}
This is what happens when I try to compile this (with Visual Studio 2019 Pro).
no instance of constructor "std::vector<_Ty, _Alloc>::vector [with _Ty=int, _Alloc=std::allocator<int>]" matches argument list
'<function-style-cast>': cannot convert from 'contt TYPE*' to 'std::CArrayForwardIt<U>'
'std::vector<int, std::allocator<int>>::vector(std::vector<int, std::allocator<int>> &&, const _Alloc &) noexcept(<expr>)': cannot convert from argument 1 from 'void' to 'const unsigned int'
Being more familiar with gcc, I have little knowledge of how to understand this.
Second attempt
I made another two further attempts at this but they were quite similar.
One was to change my class CArrayForwardIt to inherit from iterator<std::forward_iterator_tag, std::ptrdiff_t, U, U*, U&>, and to remove the using... lines at the top of the class. This didn't seem to get me any closer to a solution.
In addition, I looked at the constructor definition for std::vector. See here.
I may be misunderstanding here, but it looks like std::vector requires a InputIt type argument.
Therefore I tried to change my class to be something like this:
#include <iostream>
#include <iterator>
#include <algorithm>
template <typename U>
class forward_iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = U;
using pointer = U*;
using reference = U&;
public:
forward_iterator(pointer ptr)
: m_ptr(ptr)
{
}
// = default?
//forward_iterator(forward_iterator<U> other)
// : m_ptr(ptr)
// {
// }
reference operator*() const
{
return *m_ptr;
}
// what does this do, don't understand why operator-> is needed
// or why it returns a U* type
pointer operator->()
{
return m_ptr;
}
forward_iterator& operator++()
{
++ m_ptr;
return *this;
}
forward_iterator operator++(int)
{
forward_iterator tmp(*this);
++ (*this);
return tmp;
}
friend bool operator==(const forward_iterator& lhs, const forward_iterator& rhs)
{
return lhs.m_ptr == rhs.m_ptr;
}
friend bool operator!=(const forward_iterator& lhs, const forward_iterator& rhs)
{
return !(lhs == rhs);
}
private:
pointer m_ptr;
};
template<typename T, typename U>
auto begin(const CArray<T, U> &array)
{
return forward_iterator<U>(&array[0]);
}
template<typename T, typename U>
auto end(const CArray<T, U> &array)
{
return forward_iterator<U>((&array[array.GetCount() - 1]) + 1);
}
int main()
{
CArray<int, int> c;
// do something to c
std::vector<int> v(begin(c), end(c));
return 0;
}
This, perhaps unsurprisingly, did not compile either. At this point I became confused. std::vector appears to demand an InputIt type, which forward_iterator should work for, but it doesn't seem to make sense to redefine what forward_iterator is, even if I write this class outside of namespace std.
Question
I am fairly sure there should be a way to write an iterator class for the MFC CArray, which can be returned by begin and end functions. However, I am confused as to how to do this.
Further to the question of writing a working solution, I am beginning to wonder if there are any practical advantages to doing this? Does what I am trying to do even make sense? The raw pointer solution clearly works, so are there any advantages of investing the effort to write an iterator based solution? Can iterator solutions provide more sophisticated bounds checking, for example?
Since I managed to get this working I wanted to post a solution, hopefully I don't make too many errors transcribing it.
One thing that was not shown in the above code snippet is the fact that all these class and function definitions existed inside of namespace std. I posted another question about this earlier, and was informed that these things should not be inside namespace std. Correcting this seems to have resolved some problems and made the solution a step closer.
You can find that question here.
This is what I have so far: This is how to write an iterator for an external class which the programmer does not have access to. It also works for your own custom types or containers which you do have access to.
// How to write an STL iterator in C++
// this example is specific to the MFC CArray<T, U> type, but
// it can be modified to work for any type, note that the
// templates will need to be changed for other containers
#include <iterator>
#include <mfc stuff...>
template<typename T, typename U>
class CArrayForwardIt : public std::iterator<std::forward_iterator_tag, std::ptrdiff_t, U, U*, U&>
{
// the names used in this class are described in this list
// using iterator_category = std::forward_iterator_tag;
// using difference_type = std::ptrdiff_t;
// using value_type = U;
// using pointer = U*;
// using reference = U&;
public:
CArrayForwardIt(CArray<T, U> &array_ref, const std::size_t index)
: m_array_ref(array_ref)
, m_index(index)
{
}
// the only way I could get this to work was to make the return type
// an explicit U&, I don't know why this is required, as using
// reference operator*() const did not seem to work
U& operator*() const
{
if(m_index < m_array_ref.GetCount())
{
return m_array_ref[m_index];
}
else
{
throw std::out_of_range("Out of range Exception!");
}
}
CArrayForwardIt& operator++()
{
++ m_index;
return *this;
}
CArrayForwardIt operator++(int)
{
CForwardArrayIt tmp(*this);
++(*this);
}
friend bool operator==(const CArrayForwardIt& lhs, const CArrayForwardIt& rhs)
{
if(&(lhs.m_array_ref) == &(rhs.m_array_ref))
{
return lhs.m_index == rhs.m_index;
}
return false;
}
friend bool operator!=(const CArrayForwardIt& lhs, const CArrayForwardIt& rhs)
{
return !(lhs == rhs);
}
private:
std::size_t m_index;
CArray<T, U> &m_array_ref;
};
template<typename T, typename U>
auto begin(CArray<T, U> &array)
{
return CArrayForwardIt<T, U>(array, 0);
}
template<typename T, typename U>
auto end(CArray<T, U> &array)
{
return CArrayForwardIt<T, U>(array, array.GetCount());
}
int main()
{
CArray<int, int> array;
// do stuff to array
// construct vector from elements of array in one line
std::vector<int> vector(begin(array), end(array));
// also works with other STL algorithms
}
Note my comment about the U& operator* which produced some compiler error when written as reference operator* which might be a Visual Studio compiler bug. I'm not sure about this.
I would suggest that although this method is more difficult to implement (but not much when you know how to do it) it has the advantage of not using raw pointers which means that the iterator functions can provide proper exception throwing statements when illegal operations are attempted. For example, incrementing the iterator when it is already at the end.
Useful references:
https://lorenzotoso.wordpress.com/2016/01/13/defining-a-custom-iterator-in-c/
https://internalpointers.com/post/writing-custom-iterators-modern-cpp
For completeness, here is the simpler solution using raw pointers.
template<typename T, typename U>
auto begin(CArray<T, U> &array)
{
return &(array[0]);
}
template<typename T, typename U>
auto end(CArray<T, U> &array)
{
// get address of last element then increment
// pointer by 1 such that it points to a memory
// address beyond the last element. only works for
// storage containers where higher index elements
// are guaranteed to be at higher value memory
// addresses
if(array.GetCount() > 0)
{
return &(array[array.GetCount() - 1]) + 1;
}
else
{
return &(array[0]) + 1;
}
}
You can use these in the same way as demonstrated in the other answer, however there is also a way to use STL vector without the begin and end functions:
CArray<int, int> array; // ... do something to array
std::vector<int> vec(&array[0], &(array[array.GetCount() - 1]) + 1);
// note only works if elements guaranteed to be in continuous
// packed memory locations
but it also works with begin and end which is nicer
std::vector<int> vec(begin(array), end(array));
Here is a class that contains a boost::circular_buffer of some struct. I make a typedef for iterators into the contained circular_buffer.
My problem is this: when the doWork function is marked const, the returned value of std::upper_bound is not compatible with the MyIterator type due to the return value having boost::cb_details::const_traits. If I remove the const keyword from the function, all my compile errors go away.
To be clear the compiler error is this:
error: conversion from ‘boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::const_traits<std::allocator<Wrapper<int>::Sample> > >’ to non-scalar type ‘Wrapper<int>::MyIterator {aka boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::nonconst_traits<std::allocator<Wrapper<int>::Sample> > >}’ requested
[](const Sample& a, const Sample& b) { return a.foo < b.foo; });
Here is a self-contained example:
#include <algorithm>
#include <boost/circular_buffer.hpp>
template <typename T>
class Wrapper {
public:
struct Sample {
T foo;
};
typedef typename boost::circular_buffer<Sample>::iterator MyIterator;
Wrapper(int size) { cb.resize(size); }
void add(T val) { cb.push_back(Sample{val}); }
void doWork(T bound) const {
MyIterator iter =
std::upper_bound(cb.begin(), cb.end(), Sample{3},
[](const Sample& a, const Sample& b) { return a.foo < b.foo; });
}
boost::circular_buffer<Sample> cb;
};
int main() {
Wrapper<int> buf(100);
buf.add(1);
buf.add(5);
buf.doWork(3);
return 0;
}
So, why can't this function be const? Why does marking it const have this side-effect? I want a non-const iterator into the container, but in my real test case I don't intend to actually modify the container at all.
You're going to need a const_iterator, since you're effectively observing a const container.
Perhaps:
typedef typename boost::circular_buffer<Sample>::const_iterator MyConstIterator;
… then make iter one of these.
Someone's going to tell you that you could have avoided this with auto. That's true, but then you never would have discovered this "bug", or that const_iterators exist.
If your function is marked const then all your access to member variables will be const too.
A const container will only allow access to const_ iterators, that's just the way iterators work.
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.
Hi can anyone tell me why VS2010 gives me an error with this code, I can't see what's the problem with it?
Error code : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::vector<_Ty>' (or there is no acceptable conversion)
// Elements container
typedef std::vector<CFVFElementPtr> ElementArray;
typedef std::map<CVertexSemantic::Type, ElementArray> ElementsMap;
// Create an empty array of elements
ElementsMap::value_type::second_type allElements;
// Concatinate each std::vector found within the map
std::transform(m_elementsMap.begin(), m_elementsMap.end(),
std::insert_iterator<ElementArray>(allElements, allElements.end()),
select2nd<ElementsMap::value_type>() );
All I am trying to do is this
for (auto i = m_elementsMap.begin(); i != m_elementsMap.end(); ++i)
{
const ElementArray& elements = (*i).second;
allElements.insert(allElements.end(), elements.begin(), elements.end());
}
As a response to Pablo, I tried creating a custom iterator that accepts an array of ElementArray, but I'm now getting a bucket load of errors.
template < class Container >
class container_insert_interator
{
public:
typedef container_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename Container::const_reference const_reference;
typedef typename Container::value_type valty;
explicit container_insert_interator (Container& cont, typename Container::iterator iter)
: container(&cont), iter(iter)
{ }
this_type& operator = (typename const_reference value)
{
iter = container->insert( iter, std::begin(value), std::end(value) );
++iter;
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
Container* container; // pointer to container
typename Container::iterator iter ; // iterator into container
};
The problem is ElementsMap::value_type::second_type is ElementArray. That is, you're trying to insert instances of ElementArray into an ElementArray, which really holds instances of CFVFElementPtr.
Update: Changing your declaration of operator= from
this_type& operator = (typename const_reference value)
to
template<typename OtherContainer>
this_type& operator = ( OtherContainer const& value)
almost works. Except that neither VS 2010 or GCC 4.6.1 provide the vector::insert overload that returns an iterator. You'll probably need a newer compiler if you want your ranged insert to return an iterator to replace iter.
Changing the implementation to always insert at the end, namely
container->insert( container->end(), std::begin(value), std::end(value) );
in operator= compiles fine with GCC 4.6.1 (and, of course, you can remove all references to iter in your iterator class).
You might consider using a functor that can append elements to your target array along with std::for_each to walk the map:
struct ElementArray_appender
{
ElementArray_appender( ElementArray& dest_) : dest(dest_) {
};
void operator()( ElementsMap::value_type const& map_item) {
ElementArray const& vec( map_item.second);
dest.insert( dest.end(), vec.begin(), vec.end());
};
private:
ElementArray& dest;
};
// in whatever function:
std::for_each( m_elementsMap.begin(), m_elementsMap.end(), ElementArray_appender(allElements));
I found the answer, the poblem was with my custom iterator. The correct one that works is
template < class Container >
class container_back_insert_interator
{
public:
typedef container_back_insert_interator<Container> this_type;
typedef Container container_type;
typedef typename container_type::const_reference const_reference;
typedef typename container_type::value_type valty;
explicit container_back_insert_interator (container_type& cont)
: container(&cont)
{ }
this_type& operator = (const_reference value)
{
container->insert( container->end(), std::begin(value), std::end(value) );
return *this;
}
this_type& operator* ()
{
return *this;
}
this_type& operator++ ()
{
return *this;
}
this_type operator++ (int)
{
return *this;
}
protected:
container_type* container; // pointer to container
};
template < class Container >
inline container_back_insert_interator<Container> container_back_inserter(Container& cont)
{
return container_back_insert_interator<Container>(cont);
}
However, I must warn that if you do use this in Visual Studio 2010 you will have to implement an SGI form of std::transform. The version that ships with VS2010 for some reason throws numerous errors, all of which lie within the <xutility> header.
This std::transform works just fine.