Reputation: 1146
I'm having some trouble creating an iterator type for my class which can be used to initialize a vector. Probably best explained with some code, here's an example of what my implementation looks like:
#include <tuple>
#include <cstdint>
struct Foo
{
public:
Foo(uint8_t i) : i(i) {}
struct iterator
{
public:
using value_type = std::pair<int, bool>;
using reference = value_type;
using pointer = value_type*;
using iterator_category = std::input_iterator_tag;
bool operator == (const iterator& other) { return cur == other.cur; }
bool operator != (const iterator& other) { return !(*this == other); }
iterator& operator ++ () { if (cur > -1) --cur; return *this; }
iterator operator ++ (int) { iterator tmp = *this; ++(*this); return tmp; }
reference operator * () { return std::make_pair<int, bool>(8 - cur, foo->i & (1 << cur)); }
pointer operator -> () { static value_type v; v = *(*this); return &v; }
private:
friend Foo;
iterator(const Foo* foo, int start) : foo(foo), cur(start) {}
const Foo* foo;
int cur;
};
iterator begin() const { return iterator(this, 7); }
iterator end() const { return iterator(this, -1); }
uint8_t i;
};
The logic of what the class is doing doesn't matter; it's the fact that although I can use this iterator in a for loop, I get an error when attempting to construct a vector from it:
#include <iostream>
#include <vector>
// struct Foo...
int main()
{
Foo foo(73);
// Works, output as expected
for (auto elem : foo)
std::cout << "Position " << elem.first << " is a " << elem.second << '\n';
// Works, output as expected
for (auto it = foo.begin(), end = foo.end(); it != end; ++it)
std::cout << "Position " << it->first << " is a " << it->second << '\n';
// Error: cannot convert argument 1 from 'PowersOf2::iterator' to 'const unsigned __int64'
std::vector<std::pair<int, bool>> v(foo.begin(), foo.end());
}
cppreference tells me that std::vector
's constructor takes two iterators if InputIt satisfies InputIterator. It also tells me that the requirements for an InputIterator are
i != j
, *i
, i->m
, ++i
, (void)i++
and *i++
are validso I'm not sure what's gone wrong. Any help appreciated!
Upvotes: 4
Views: 341
Reputation: 29023
According to cccpreference.com the std::vector
constructor that takes iterators "[...] only participates in overload resolution if InputIt satisfies InputIterator, to avoid ambiguity with the overload (2).".
To satisfy InputIterator a type must satisfy Iterator. In turn, Iterator
requires the type to provide several type alias, including difference_type
which you've omitted.
Try adding the public type alias using difference_type = std::ptrdiff_t;
to your iterator type.
Upvotes: 3