iterator Overload Member Selection vs Indirection Operator - c++

So in the interest of creating a Minimal. Complete, Verifiable Example I have created a toy iterator here (I know it's not perfect, it's just for the purposes of asking a question):
class foo : public iterator<input_iterator_tag, string> {
string _foo;
static const size_t _size = 13;
public:
const string& operator*() { return _foo; }
const foo& operator++() {
_foo += '*';
return *this;
}
const foo operator++(int) {
auto result = *this;
_foo += '*';
return result;
}
bool operator==(const foo& rhs) { return _foo.empty() != rhs._foo.empty() && _foo.size() % _size == rhs._foo.size() % _size; }
bool operator!=(const foo& rhs) { return !operator==(rhs); }
};
I read that an InputIterator needs to have defined the Member Selection Operator. The Indirection Operator makes sense, but a Member Selection Operator is confusing to me here. How would an Member Selection Operator be implemented for foo?

const string* operator->() const { return &_foo; }
Example usage:
foo i;
++i;
assert(i->length() == 1);
The way this works is that the compiler will generate repeated calls to operator-> until the return type is a raw pointer (so in this case just one call to foo::operator->), then do the regular member selection operation on that pointer.

The operator->() should return a pointer type of the type the container holds that the iterator is used on. So if you have a container that holds a std::string then the iterator::operator-> should return a std::sting*. In your case since you derive from std::iterator you can use the pointer typedef for the return type.

Related

How do move-only iterator implement postfix ++ operator?

What is the right way to implement an iterator that iterates over a Recordset provided below in C++ style?
class Recordset
{
public:
Recordset(const Recordset&) = delete;
Recordset& operator = (const Recordset&) = delete;
Recordset(Recordset&& other) noexcept = default;
Recordset& operator = (Recordset&&) = default;
//Moves to the next record. Returns false if the end is reached.
bool Next();
//Gets the current record as an instance of type T.
template <class T>
void Get(T& val);
};
my idea is that I probably do something like this:
template <class T>
class Iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
Iterator() = default;
Iterator(Recordset s) : m_i(std::move(s))
{
try_next();
}
Iterator(const Iterator&) = delete;
Iterator& operator = (const Iterator&) = delete;
Iterator(Iterator&& other) = default;
Iterator& operator = (Iterator&& other) = default;
T* operator-> () { return cur(); }
T* operator* () { return cur(); }
bool operator== (const Iterator& other) const noexcept
{
//They both are end().
return !m_v && !other.m_v;
}
bool operator!= (const Iterator& other) const noexcept
{
return !operator==(other);
}
Iterator& operator++ ()
{
this->try_next();
return *this;
}
Iterator operator++ (int)
{
Iterator tmp = *this; //would not compile.
this->try_next();
return tmp;
}
private:
bool try_next()
{
if (m_i.Next())
{
T val;
m_i.Get(val);
m_v = val;
return true;
}
return false;
}
T* cur()
{
T& val = *m_v;
return &val;
}
Recordset m_i;
std::optional<T> m_v;
};
template <class T>
std::ranges::subrange<Iterator<T>> make_range(Recordset& s)
{
return std::ranges::subrange(Iterator<T>(s), Iterator<T>{});
}
and use it as follows:
struct Record { int x; std::string y; };
int main()
{
Recordset s;
for (Record& r : make_range(s))
{
std::cout << r.x << r.y << std::endl;
}
return 0;
}
The frist question is how do I implement Iterator operator++ (int) if both Recordset and Iterator are move-only? (temp and this can't point to different records, because there is only one current record in the recordset). Does C++20 require it?
The second question is it a good idea to implement end() in this way? (end() is a simply an iterator containing an empty optional)
Single pass move-only input iterators (A c++20 std::input_iterator) are only required to be weakly incremental, where (void) ++i has the same effect as (void) i++. You can simply have void operator++(int) { ++*this; }. Older requirements for iterators (Cpp17InputIterator) requires iterators to be copyable, and require operator++ to return that copy.
And for your second question, you might want to use a sentinel type, something like:
template<typename T>
bool operator==(const Iterator<T>& it, std::default_sentinel_t) {
return !it.m_v;
}
// != can be rewritten from ==, so no need to write one
template <class T>
auto make_range(Recordset& s)
{
return std::ranges::subrange(Iterator<T>(s), std::default_sentinel);
}
And if you need to work with a algorithm that can't use separate sentinel types, use ranges::common_view. Your current solution also works, except you need to have this == &other || (!m_v && !other.m_v);.

C++ how to make polymorphic wrapper class around smart pointer?

Hello I am writing code for school project.
In my current implementation I am using polymorphism in some cases. Like for example when I have a set or a vector:
std::vector<Parent *> vec;
vec.push_back(new Child1()); // adding instance of derived class
vec.push_back(new Child2()); // adding other instance of derived class
I can use this code to add objects of derived classes, but in case of using a set for example, I cannot prevent duplicated by using this method, because the set will compare the memory address to another, not the objects themselves, so I want to use wrappers. On another note, my teacher suggests to use smart pointers, like unique_ptr or shared_ptr so that memory is properly cleaned up. I find the second option to be easier to work with. In any case even if I have:
std::set<std::shared_ptr<Parent>> s;
s.insert(std::make_shared<Child1>(Child1());
// ...
s.insert(std::make_shared<ChildN>(ChildN());
It still works just with regular pointers and duplicates are allowed. So I want to write a wrapper class to prevent this from happening and I have something like this:
template<typename T>
class PolymorphicWrapper {
private:
std::shared_ptr<T> ptr;
public:
PolymorphicWrapper(const std::shared_ptr<T> &ptr) : ptr(ptr) {}
const std::shared_ptr<T> &getPtr() const {
return ptr;
}
void setPtr(const std::shared_ptr<T> &ptr) {
PolymorphicWrapper::ptr = ptr;
}
bool operator==(const PolymorphicWrapper &rhs) const {
return *ptr == *rhs.ptr;
}
bool operator!=(const PolymorphicWrapper &rhs) const {
return rhs != *this;
}
bool operator<(const PolymorphicWrapper &rhs) const {
return *ptr < *rhs.ptr;
}
bool operator>(const PolymorphicWrapper &rhs) const {
return rhs < *this;
}
bool operator<=(const PolymorphicWrapper &rhs) const {
return rhs >= *this;
}
bool operator>=(const PolymorphicWrapper &rhs) const {
return *this >= rhs;
}
};
But this approach doesn't work with derived classes at all!
For example:
std::set<PolymorphicWrapper<Parent>> s;
s.insert(PolymorphicWrapper<Parent>(std::make_shared<ChildN>(ChildN()); // doesn't work
Is there a simple fix? I am not too good with programming and have trouble understating hard solutions. But it is an exam I have to pass to keep going with other subjects.
The std::set template lets you specify a key comparison function. Instead of messing with the pointer class, just use a comparison function for the pointers that compares what they point to.
See: https://en.cppreference.com/w/cpp/container/set

Making a class iterable with iteration order depending on class implementation

I have a type that has two different implementations, using different data structures. One stores its data in a std::vector<std::unique_ptr<Data>>, the other in a 2D array Data***.
The elements are stored in a specific order, meaning that their position in the vector or 2D array matters. As such, when wanting to iterate over all data in my class, my for loops are dependent on the implementation, being basically one of the following:
for(auto& data : myClass->dataVector) { do Stuff }
for(int x = 0; x < myClass->xVals; x++) {
for(int y = 0; y < myClass->yVals; y++ {
do Stuff with myClass->dataArr[x][y]
}
}
Since the two version of my class share similarities, I want to have a proper parent class that is implemented by two inheriting classes, hopefully in a way that I can iterate over my data by simply doing something such as:
for(auto& data : myClass) { doStuff }
(notice how myClass acts as if it was a collection itself, even if it actually is just a container of a collection)
where the way and order in which this iteration works obviously depends on the implementation of the class.
How do make my class iterable in such a manner?
Lets assume you have a base with all the data, and two derived classes with traversal behavior:
class Base {
public:
std::vector<...> dataVector;
int xVals;
int yVals;
Data** dataArr;
};
Defining .begin() and .end() makes a class iterable with for_each. A simple forwarding to the vector iterators is enough for the first case:
class DerivedA : private Base {
public:
auto begin() { return this->dataVector.begin(); }
auto begin() const { return this->dataVector.begin(); }
auto end() { return this->dataVector.end(); }
auto end() const { return this->dataVector.end(); }
}
For the Data** case you will have to define a custom iterator:
class iterator {
public:
using value_type = Data;
using difference_type = std::ptrdiff_t;
using reference = Data&;
using pointer = Data*;
using iterator_category = std::forward_iterator_tag;
iterator() : m_base(), m_idx(0) { }
iterator(Base* b, std::size_t idx) : m_base(b), m_idx(idx) { }
reference operator*() const { return m_base->dataArr[m_idx / m_base->yVals][m_idx % m_base->y_vals]; }
pointer operator->() const { return &**this; }
friend iterator& operator++(iterator& rhs) { ++rhs.m_idx; return rhs; }
friend iterator operator++(iterator& lhs, int) { auto cp = lhs; ++lhs; return cp; }
friend bool operator==(iterator lhs, iterator rhs) { return lhs.m_idx == rhs.m_idx; }
friend bool operator!=(iterator lhs, iterator rhs) { return !(lhs == rhs); }
private:
Base* m_base;
std::size_t m_idx;
};
class const_iterator {
// equivalent but const. (reference = const Data& and pointer = const Data*)
// Make sure iterator is convertible to const_iterator.
};
class DerivedB : private Base {
iterator begin() { return { this, 0 }; }
const_iterator begin() const { return { this, 0 }; }
iterator end() { return { this, this->xVals*this->yVals }; }
const_iterator end() const { return { this, this->xVals*this->yVals }; }
};

How to define iterator for a special case in order to use it in a for loop using the auto keyword

I would like to define the subsequent code in order to be able to use it like
"for (auto x:c0){ printf("%i ",x); }"
But I do not understand something and i have searched it for some time.
The error I get is:
error: invalid type argument of unary ‘*’ (have ‘CC::iterator {aka int}’)
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int iterator;
public: iterator begin(){return (iterator)0;}
public: iterator end(){return (iterator)0x20;}
public: int& operator*(iterator i){return this->a[(int)i];}
} ;
int main(int argc, char **argv)
{ class CC c0;
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}
It seems you are trying to use int as you iterator type using the member operator*() as the deference operations. That won't work:
The operator*() you defined is a binary operator (multiplication) rather than a unary dereference operation.
You can't overload operators for built-in types and an iterator type needs to have a dereference operator.
To be able to use the range-based for you'll need to create a forward iterator type which needs a couple of operations:
Life-time management, i.e., copy constructor, copy assignment, and destruction (typically the generated ones are sufficient).
Positioning, i.e., operator++() and operator++(int).
Value access, i.e., operator*() and potentially operator->().
Validity check, i.e., operator==() and operator!=().
Something like this should be sufficient:
class custom_iterator {
int* array;
int index;
public:
typedef int value_type;
typedef std::size_t size_type;
custom_iterator(int* array, int index): array(array), index(index) {}
int& operator*() { return this->array[this->index]; }
int const& operator*() const { return this->array[this->index]; }
custom_iterator& operator++() {
++this->index;
return *this;
}
custom_iterator operator++(int) {
custom_iterator rc(*this);
this->operator++();
return rc;
}
bool operator== (custom_iterator const& other) const {
return this->index = other.index;
}
bool operator!= (custom_iteartor const& other) const {
return !(*this == other);
}
};
You begin() and end() methods would then return a suitably constructed version of this iterator. You may want to hook the iterator up with suitable std::iterator_traits<...> but I don't think these are required for use with range-based for.
Dietmar Kühl explained well why your code does not work: you cannot make int behaving as an iterator.
For the given case, a suitable iterator can be defined as a pointer to int. The following code is tested at ideone:
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int* iterator;
public: iterator begin() {return a;}
public: iterator end() {return a+0x20;}
} ;
int main(int argc, char **argv)
{
class CC c0;
int i = 0;
for (auto& x:c0){
x = ++i;
}
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}

C++: Using base class's private members in equality test

I would like the following to compile, but it does not:
template <typename T>
struct Odp
{
public:
operator*() const
{
return m_p;
}
T* operator->() const
{
return m_p;
}
T** operator&()
{
return &m_p;
}
private:
T* m_p;
};
struct Ftw : public Odp<int>
{
bool operator==(const Ftw& rhs)
{
return m_p == rhs.m_p; // C2248 cannot access private member
}
};
Is there any way to make this work? I can't modify Odp.
Odp overloads operator* to return m_p. You can invoke the operator on *this and rhs:
struct Ftw : public Odp<int>
{
bool operator==(const Ftw& rhs) const
{
return **this == *rhs;
}
};
The operator* overload is a bit unusual, however: it should probably return *m_p instead, since operator-> returns m_p (this would result in your class having consistent pointer-like semantics). If you did this, you would then have to do the following to do the comparison:
return &**this == &*rhs; // or explicitly as:
return &this->operator*() == &rhs.operator*();
This is getting a bit messy, and it won't necessarily work if the unary & is overloaded for T (but, you really, really shouldn't do that...). You can also obtain the pointer by explicitly calling operator->, which might be preferable:
return this->operator->() == rhs.operator->();
The real question is, "what is this Odp, why are you using it, and why can you not modify it?"
On an unrelated note, your operator== should either be implemented as a const member function or, preferably, as a friend function:
bool operator==(const Ftw& rhs) const { /* ... */ }
friend bool operator==(const Ftw& lhs, const Ftw& rhs) { /* ... */ }
On another unrelated note, overloading the unary & is almost certainly a bad idea.
The compiler is telling you that m_p is private. If you want to access m_p in the derived class you need to make it either protected or public.
Since Odp is giving the pointer out for free in its methods (even the address of it, OMG! it's like making door with many locks and then giving the keys to every thief around), you can just do
bool operator==(const Ftw& rhs)
{
return **this == *rhs;
}
Had Odp implemented its own comparison operator, you could use it like this:
bool operator==(const Ftw& rhs)
{
return Odp<int>::operator==(rhs) && ... other conditions ...;
}
If you can't modify Odp, you can call operator->() explicitly. It returns what you need and should get inlined.