I can iterate through a C-style array this way:
char foo[3] = { 'a', 'b', 'c' };
for (auto it = std::begin(foo); it != std::end(foo); ++it)
{
*it = 'k'; //values of foo are correctly modified
}
Now suppose I want to wrap the array inside a class, and expose a begin()
and end()
methods that return the relative iterators.
I tried the following:
template<size_t size>
class StackMemPolicy
{
private:
char mem[size];
public:
typedef typename std::iterator<std::input_iterator_tag, char> iter;
iter begin()
{
return std::begin(mem);
}
iter end()
{
return std::end(mem);
}
}
It seems the returned type declaration is wrong, and the following calling code don't compile:
StackMemPolicy<4> bar;
for (auto it = bar.begin(); it != bar.end(); ++it)
{
*it = 'k';
}
The error is the following:
Error 1 error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'StackMemPolicy<4>::iter' (or there is no acceptable conversion)
Can anyone tell me where's my error?
std::iterator
is meant to be used as a base class. From 24.4.2/1:
namespace std {
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
}
It only gives you some typedefs and won't magically implement all the required operators. In your case, begin()
and end()
should probably just return char*
, which already has specializations for std::iterator_traits
.
However, if your iterator has to be smarter (maybe this is some sort of circular buffer, for example), you would have to create your own iterator class and implement the required operators. For that iterator to work with various features in the standard library (such as std::iterator_traits
), you'll need predefined typedefs such as value_type
, iterator_category
, etc.
Since getting those right can sometimes be tricky, std::iterator
will define those for you based on the given template parameters. Here's an example of using std::iterator_traits
with an iterator.
Note that as of C++17, std::iterator
has been deprecated for various reasons. This post has some workarounds.
It works for me if I change:
typedef typename std::iterator<std::input_iterator_tag, char> iter;
to:
typedef char * iter;
Unless you don't want to modify the behavior, you should just return std::begin(mem)
which is nothing more than a char *
.
See see 2'nd overload
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With