I've got this template:
template<typename C,class F>
class filtered_cont{
C& container;
F filter;
class const_iterator{
//my iterator implementation
}
const_iterator begin(){
//...
}
}
C- container and F is filter. I'd like to ask how to implement my own begin() method that it will return first valid element. I got something like this, but I get errors
const_iterator begin() const{
for (const_iterator it=cont.begin(); it!=const_iterator(); it++) {
if(pred(*it)) return it;
}
return const_iterator();
}
I think the wrong part is it=cont.begin(), but I don't really know how to get begin() iterator.
Error:
no viable conversion from 'iterator' (aka '__list_iterator<value_type, __void_pointer>') to 'filter_view<std::__1::list<unsigned char,
std::__1::allocator<unsigned char> >, is_even>::const_iterator
You'll need to use the container's iterator, not your own. Something like this:
const_iterator begin() const{
for (typename C::const_iterator it=cont.begin(); it!=cont.end(); it++) {
if(pred(*it)) return const_iterator(it);
}
return const_iterator();
}
The error message states what is missing: your const_iterator needs an [implicit] constructor from typename Container::const_iterator:
template <typename C, typename F>
class filtered_cont<C, F>::const_iterator {
public:
const_iterator(typename C::const_iterator it);
// ...
};
If you change your initialization slightly, you can make the conversion explicit which is probably a good idea:
for (const_iterator it(cont.begin()); ... ) {
...
}
Personally, I would expect to use the filtering logic to be contained by the iterator as it needs to have this logic anyway, e.g., when moving to the next element. The logic itself should probably be
std::find_if(it, cont.end(), filter);
Your begin function looks fine (in pri).
Instead of defining a const_iterator type, you may want to define a iterator type, and then define the const_iterator type as the const version of it.
But, regardless, your class will need to provide a way to get from an arbitrary input iterator, to the desired type of iterator. That means you needs constructor, and a general approach. I am not certain how one should do that, but I would guess your own iterator stores the incoming iterator (in a C::iterator field), then passes on any calls to it.
Related
I'm trying to create my own data-structure that can determine if a value is an element within it in O(1) time with a hash-map.
I'm working on adding more member functions so that it's more similar to the STL containers. Here's what I currently have that's relevant to the problem:
template <class T>
class setfind {
private:
long long _size = 0;
unordered_map<T, bool> _set;
public:
// constructors
setfind() {}
// initialize from some iterable
template <class InputIterator>
setfind(InputIterator beg, InputIterator en){
_size = en - beg;
while (beg != en){
_set[*beg] = true;
beg++;
}
}
bool contains(const T &val){
return _set[val];
}
bool contains(const T &&val){
return _set[val];
}
};
As you can see, its core is the unordered_map. I want to write a member function that returns a begin iterator to the _set variable. I tried putting this in:
template <class InputIterator>
InputIterator begin()
{
return _set.begin();
}
but that led to a compilation error saying that there was no matching member function.
I don't know enough about iterators and template-classes to fix this. Does anyone know how to implement it or what's wrong? Are there any good resources so that I can learn more about this?
Also some optimization tips for this class would be appreciated because this is going to be used under a time-limit.
EDIT: I’m restricted to using c++11
EDIT2: Fixed a bug in the constructor
EDIT3: Memory leaks and best-practices will not be an issue
I see several issues with your code.
You don't need the _size member at all, get rid of it and use _set.size() when needed.
In your constructor, while (*beg != *en) needs to be while (beg != en) instead. Or better, just geet rid of the manual loop altogether and use the std::unordered_map constructor that takes an iterator pair as input:
// initialize from some iterable
template <class InputIterator>
setfind(InputIterator beg, InputIterator en) : _set(beg, en) {}
In your contains() methods, use _set.find() or _set.contains() instead of _set.operator[] to avoid val begin added to the _set if it does not already exist. Also, it does not make sense to take a const rvalue reference, so just get rid of that overload altogether:
bool contains(const T &val) const
{
return _set.find(val) != _set.end();
// or:
// return _set.contains(val);
}
And lastly, for your begin() method, just use auto for the return type instead of a template, let the compiler deduce the necessary type, eg:
auto begin()
{
return _set.begin();
}
UPDATE: apparent auto return type deduction was introduced in C++14. So, for C++11, you will just have to state the type explicitly, still don't use a template for it, eg:
unordered_map<T, bool>::iterator begin()
{
return _set.begin();
}
Or:
auto begin() -> unordered_map<T, bool>::iterator
{
return _set.begin();
}
Or:
auto begin() -> decltype(_set.begin())
{
return _set.begin();
}
You can simplify this by declaring an iterator alias in your class (which you should do anyway, if your goal is to make your class act like a standard container), eg:
template <class T>
class setfind {
private:
unordered_map<T, bool> _set;
public:
using iterator = unordered_map<T, bool>::iterator;
...
iterator begin(){
return _set.begin();
}
};
I have classes which are usually using standard containers as underlying fields. For example, I have a class
template <typename T>
class Vec_3D
{
public:
/* ... */
std::array<T, 3> vec;
/* ... */
};
which has only one variable vec and the rest are just functions I need when working with vectors. I want to be able to use range-based for loop such as
Vec_3D<double> vec;
for (double val : vec) {/*...*/}
which should obviusly iterate over std::array<double, 3>.
How to implement iterators in my class which should in turn call iterators of std::array<T, 3>?
I started with this question and tried to define iterators in my class as
typedef std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&> iterator;
typedef std::iterator<std::random_access_iterator_tag, const T, ptrdiff_t, const T*, const T&> const_iterator;
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.end(); }
but got compiling errors
error: no match for ‘operator!=’ (operand types are ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’ and ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’)
and operator++, operator*
std::iterator is (was) a helper type to define the typedefs that a typical iterator requires. These typedefs within the class in turn make std::iterator_traits work with your iterator.
It does not, however, actually implement the required operations for you.
It was deprecated, because the std committee didn't like specifying that standard iterators had to have those typedefs, and writing the typedefs was not much bulkier than figuring out what arguments to pass to the std::iterator template.
The easy thing to do here is to just steal your underlying container's iterator. This makes your abstraction leak, but it is efficient and easy.
template <typename T>
struct Vec_3D {
using container=std::array<T, 3>;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return vec.begin(); }
iterator end() { return vec.end(); }
const_iterator begin() const { return vec.begin(); }
const_iterator end() const { return vec.end(); }
private:
/* ... */
container vec;
/* ... */
};
If you don't want to expose your underlying container type, if you are willing to guarantee your underlying container is a contiguous buffer you can do:
template <typename T>
struct Vec_3D {
using iterator=T*;
using const_iterator=T const*;
iterator begin() { return vec.data(); }
iterator end() { return vec.data()+vec.size(); }
const_iterator begin() const { return vec.data(); }
const_iterator end() const { return vec.data()+vec.size(); }
private:
/* ... */
std::array<T,3> vec;
/* ... */
};
as pointers are valid iterators.
If you find you are writing this "I am a modified container" boilerplate too much, you can automate it:
template<class Container>
struct container_wrapper {
using container=Container;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return m_data.begin(); }
iterator end() { return m_data.end(); }
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
protected:
Container m_data;
};
and then
template <typename T>
class Vec_3D:private container_wrapper<std::array<T,3>> {
// ...
};
but even that might be a bit much, why not just:
template <typename T>
class Vec_3D:public std::array<T,3> {
// ...
};
It is true that deleting Vec_3D through a pointer to base is undefined behavior, but who deletes pointers to standard containers?
If this worries you:
template <typename T>
class Vec_3D: private std::array<T,3> {
using container = std::array<T,3>;
using container::begin();
using container::end();
// ...
};
lets you inherit privately, then bring certain operations back into scope.
A range-based for loop only requires that your class have begin() and end() methods (or overloads of std::begin() and std::end()) that return iterators. It doesn't care where those iterators come from. So, the simplest solution is to just use the array's own iterators instead of trying to define your own, eg:
template <typename T>
class Vec_3D
{
public:
typedef typename std::array<T, 3> array_type;
typedef typename array_type::iterator iterator;
typedef typename array_type::const_iterator const_iterator;
// or:
// using array_type = std::array<T, 3>;
// using iterator = array_type::iterator;
// using const_iterator = array_type::const_iterator;
...
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.cend(); }
...
private:
array_type vec;
};
std::iterator is a base class only, its basically a container for some traits, but if you wanted to use it to implement your own iterator class you'd need to derive from it.
However you don't need to use it, there was a proposal to deprecate it, you could just define those traits directly in an iterator that you write. The following question has info on the proposal and help with implementing an iterator class:-
Preparation for std::iterator Being Deprecated
At the moment you're defining your container's iterator types using that base, not a class that can actually do any iterating, which is why it fails.
You expose the array as a public member. If you're happy to expose that your vec_3d is implemented using an array (whether you continue to expose the member array publicly or not) then you could just use the array's iterators - its not clear from the question that your iterator needs any bespoke behaviour just because your container adds some functionality.
I am trying to make a custom iterator and I am struggling with syntax part of how to define/declare and eventually access it. Below is my attempt, which results in below error:
Error C2440 'initializing': cannot convert from 'int' to 'int *'
If someone can point me to right way to define/declare it - it would be great, for I believe my access method is standard.
Declaration
template <typename T>
class ddeque
{
public:
typedef T* iterator;
T& begin();
T& end();
}
Definition
template<typename T>
T& ddeque<T>::begin()
{
iterator = &(this->unified_array());
return iterator;
}
template<typename T>
T& ddeque<T>::end()
{
iterator = &(this->unified_array + this->size());
return iterator;
}
Access part --
In test.cpp file
// Comparing values from custom template with standard template
typename ddeque<T>::iterator itt = a.begin();
typename deque<T>::iterator ittg = g.begin();
while ((itt != a.end()) && (ittg != g.end()))
{
if (display)
{
cout << *itt << " ";
}
++itt;
++ittg;
}
P.S : I have just kept relevant part of iterator - please let me know if additional code snippet is required.
As pointed by SO member АндрейБеньковский I was returning reference instead of pointer- correct solution for definition would be ( what got it working )
Declaration:
template <typename T>
class ddeque
{
public:
typedef T* iterator;
iterator begin();
iterator end();
}
Definition
template
T* ddeque::begin()
{
iterator = &(this->unified_array());
return iterator;
}
template<typename T>
T* ddeque<T>::end()
{
iterator = &(this->unified_array + this->size());
return iterator;
}
In general:
how to define and access custom iterator
You should make a contaner class and an iterator class. The latter should be derived from std::iterator<>. You have to specify iterator tag, return value, ect. Depending on the iterator tag, you should be implementing the operators (increment, decrement, ect.). (Or better, implement everything you can which has a maximum of logarithmic complexity, then set best iterator tag.)
So begin, and end should be returning your iterator. Take a look at some stl container implementations, they are not so hard to read.
In your code
ou have made a typdef T* iterator;. This line makes another name for the pointer to T type. For readability, and to make it easier to change later, you should be returning iterator with begin and end, so:
iterator begin();
iterator end();
In the definition of the above functions, you cannot assign a value to the iterator type, I suggest returning the pointer (or iterator), for example in end():
return this->unified_array + this->size();
I think unified_array is a pointer, so I used it that way.
I'm currently using a third-party library which contains a class that only provides indexed lookup, i.e. operator[].
I'd like to do a range-based for loop on this class's contents. However, having never written an iterator or iterator adapter, I'm quite lost. It seems that writing iterators is not a straightforward task.
My desired usage is:
for(auto element : container)
{
...
}
Instead of having to write:
for(int i = 0; i < container.size(); ++i)
{
auto element = container[i];
...
}
How can this be achieved? Does Boost provide this functionality?
Writing iterators is actually a rather straightforward task, but it gets extremely tedious. Since your container supports indexing by an integer, I assume its iterators would fall into the random access iterator category (if they existed). That needs a lot of boilerplate!
However, to support the range-based for loop, all you'll need is a forward iterator. We'll write a simple wrapper for the container that implements the forward iterator requirements, and then write two functions Iterator begin(Container&) and Iterator end(Container&) that enable the container to be used in the range-based for loop.
This Iterator will contain a reference to the container, the size of the container, and the current index within that container:
template<template<typename> class C, typename T>
class indexer : public std::iterator<std::forward_iterator, T>
{
public:
indexer(C<T>& c, std::size_t i, std::size_t end)
: c_(std::addressof(c)), i_(i), end_(end) {}
T& operator*() const {
return c_[i_];
}
indexer<C, T>& operator++() {
++i_;
return *this;
}
indexer<C, T> operator++(int) {
auto&& tmp = *this;
operator++();
return tmp;
}
bool operator==(indexer<C, T> const& other) const {
return i_ == other.i_;
}
bool operator!=(indexer<C, T> const& other) const {
return !(*this == other);
}
private:
C<T>* c_;
std::size_t i_, end_;
};
Inheriting from std::iterator conveniently declares the appropriate typedefs for use with std::iterator_traits.
Then, you would define begin and end as follows:
template<typename T>
indexer<Container, T> begin(Container<T>& c) {
return indexer<Container, T>(c, 0, c.size());
}
template<typename T>
indexer<Container, T> end(Container<T>& c) {
auto size = c.size();
return indexer<Container, T>(c, size, size);
}
Switch out Container for whatever the type of container is in your example, and with that, your desired usage works!
The requirements and behavior of all the various kinds of iterators can be found in the tables of section 24.2.2 of the standard, which are mirrored at cppreference.com here.
A random-access iterator implementation of the above, along with a demo of usage with a simple vector_view class can be found live on Coliru or ideone.com.
You can do the following:
1) define your own iterator It that contains, inside, a ref ref to your container container and an index i. When the iterator is dereferenced, it returns ref[i] by reference. You can write it yourself or you can use boost for help, it has an iterator library to easily define your own iterators. Constructor should accept a container& and a size_t. You can make also the const_iterator if this concept applies.
2) When operator++ is invoked on one iterator, it simply does ++i on the internal member. operator== and operator!= should simply compare i. You can assert, for security, that both iterators are coherent, that means their refs point to the same object.
3) add begin and end to your container class or, if this is not possible, define a global begin and end that accept your container& c. begin should simply return It(c, 0). end should return It(c, c.size()).
There could be a problem copying the iterators as they contain a reference and some other minor details, but I hope the overall idea is clear and correct.
How do I acquire a const_iterator (of some container class) from an iterator (of that container class) in C++? What about a const_iterator from an insert_iterator? The resulting iterator should point at the same spot as the original does.
Containers are required to provide iterator as a type convertible to const_iterator, so you can convert implicitly:
Container::iterator it = /* blah */;
Container::const_iterator cit = it;
std::insert_iterators are output iterators. This gives no way to convert them to a regular Container::iterator which must be a forward iterator.
Another kind of insert iterator may allow such a thing, but those obtained from the standard functions don't.
I guess you can write your own wrapper around std::insert_iterator that exposes the protected member iter, though:
template <typename Container>
class exposing_insert_iterator : public std::insert_iterator<Container> {
public:
exposing_insert_iterator(std::insert_iterator<Container> it)
: std::insert_iterator<Container>(it) {}
typename Container::iterator get_iterator() const {
return std::insert_iterator<Container>::iter;
}
};
// ...
std::insert_iterator<Container> ins_it;
exposing_insert_iterator<Container> exp_it = ins_it;
Container::iterator it = exp_it.get_iterator();
You can convert them. Example:
std::vector<int> v;
std::vector<int>::iterator it = v.begin();
std::vector<int>::const_iterator cit = it;
But I guess that is not the answer you are seeking. Show me code. :-)