I have a C++ library (with over 50 source files) which uses a lot of STL routines with primary containers being list and vector. This has caused a huge code bloat and I would like to reduce the code bloat by creating another library which is essentially a wrapper
over the list and vector.
I basically need a wrapper around std::list which works perfectly for the list container of any type.
Shown below is my list wrapper class.
template<typename T>
class wlist
{
private:
std::list<T> m_list;
public:
wlist();
typedef std::list<void*>::iterator Iterator;
typedef std::list<void*>::const_iterator CIterator;
unsigned int size () { return m_list.size(); }
bool empty () { return m_list.empty(); }
void pop_back () { m_list.pop_back(); }
void pop_front () { m_list.pop_front(); }
void push_front (const T& item) { m_list.push_front(item); }
void push_back (const T& item) { m_list.push_back(item); }
bool delete_item (void* item);
T& back () { return (m_list.empty()) ? NULL : m_list.back();}
T& front () { return (m_list.empty()) ? NULL : m_list.front();}
Iterator erase() { return m_list.erase(); }
Iterator begin() { return (Iterator) m_list.begin(); }
Iterator end() { return (Iterator) m_list.end(); }
};
File1.h:
class label{
public:
int getPosition(void);
setPosition(int x);
private:
wlist<text> _elementText; // used in place of list<text> _elementText;
}
File2.h:
class image {
private:
void draw image() {
//Used instead of list<label*>::iterator currentElement = _elementText.begin();
wlist<label*>::iterator currentElement = _elementText.begin();
currentElement->getPosition(); // Here is the problem.
currentElement ++;
}
}
Invoking getPosition() bombs with the following error message:
error: request for member `getPosition' in `*(¤tElement)->std::_List_iterator<_Tp>::operator-> [with _Tp = void*]()', which is of non-class type `void*'
Type casting getPosition() to label type didn't work. Additionally my iterators are of type void*.
I think the problem is that the line
currentElement->getPosition();
won't work because currentElement is an iterator over void*s, not labels. Since iterators over some type T act like T*s, this means that your currentElement iterator acts like a label**, and so writing the above code is similar to writing
(*currentElement).getPosition();
Here, the problem should be a bit easier to see - *currentElement is a label*, not a label, and so you can't use the dot operator on it.
To fix this, trying changing this code to
((label *)(*currentElement))->getPosition();
This dereferences the iterator and typecasts the void* to get a label*, then uses the arrow operator to call the getPosition() function on the label being pointed at.
Your iterator types seem to be declared in terms of std::list<void*>::iterator. This doesn't sound right to me...
Related
What I want to achieve is probably easily explained: Consider I have an abstract class that I know will contain multiple objects of known type. However the actual container holding these objects will be implemented in sub-classes.
In my abstract base class I now want to provide an interface to iterate over these objects. Given that I don't know (or rather don't want to fix) the type of container, I thought that iterators would probably be my best bet.
A conceptual declaration of this class might look like this:
class MyClass {
public:
// Other interface methods, e.g. size()
virtual Iterable<MyObject> objects() = 0;
};
The intention here is that I'll be able to iterate over the nested objects of my class like this:
MyClass *class = new ImplementationOfClass();
for (const MyObject &obj : class->objects()) {
// Do stuff with obj
}
The issue I am facing however is that I can't seem to figure out how Iterable<MyObject> should be defined. The key property of this object is that at the time of defining this class I can only specify that the returned value will be iterable (using STL-style iterators) and will yield objects of type MyObject when the used iterator is dereferenced.
Normally I would use an abstract class on its own for this but it seems that this is very tricky (impossible?) since iterators are always passed by value and thus to my knowledge no Polymorphism is possible.
Questions dealing with how to pass arbitrary iterator types as arguments into a function always come up with the "use templates" answer. However I think in my case I can't use templates for that. This assumption might be wrong though, so feel free to correct me.
Essentially the barrier I always run into is that at some point I have to write down the iterator type explicitly which in my case I can't. I thought about using a template for that but this would then inhibit proper Polymorphism (I think?) because the user of that abstract interface seems to have the burden of explicitly initializing the correct template. The whole point of all of this however is that the caller does not have to care about the underlying structure.
TL;DR: Is there a way to create an interface class that only promises to be iterable and that dereferencing an iterator will yield an object of type T?
With the help of #FrançoisAndrieux and a hint from https://stackoverflow.com/a/4247445/3907364, I was able to come up with an approach to my problem.
Essentially the idea is to create an iterator-wrapper that stores a function to obtain an object of the given type if given an index. That index is then what is iterated on.
The nice thing about this is that the iterator interface is fixed by specifying the type of object that dereferencing it should return. The polymorphism comes into play by making the member function objects() virtual so that each sub-class can construct the iterator itself, providing a custom function pointer. Thus as long as there is a way to map an index to the respective element in the container (whichever is used), this trick is usable.
Note that you can either directly use pointers to e.g.std::vector<T>::at or create a custom function that will return the respective element.
Here's the implementation for the iterator (The implementation could probably be improved upon but it seems to get the job done):
template< typename T > struct iterator_impl {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T *;
using reference = T &;
using access_function_t = std::function< T &(std::size_t) >;
// regular Ctor
iterator_impl(std::size_t start, access_function_t &func, const void *id)
: m_index(start), m_func(func), m_id(id) {}
// function-move Ctor
iterator_impl(std::size_t start, access_function_t &&func, const void *id)
: m_index(start), m_func(func), m_id(id) {}
// copy Ctor
iterator_impl(const iterator_impl &) = default;
// move ctor
iterator_impl(iterator_impl &&other) {
std::swap(m_index, other.m_index);
m_func = std::move(other.m_func);
std::swap(m_id, other.m_id);
}
// copy-assignment
iterator_impl &operator=(const iterator_impl &other) = default;
// prefix-increment
iterator_impl &operator++() {
++m_index;
return *this;
}
// postfix-increment
iterator_impl operator++(int) {
iterator_impl old = *this;
++(*this);
return old;
}
bool operator==(const iterator_impl &other) { return m_index == other.m_index && m_id == other.m_id; }
bool operator!=(const iterator_impl &other) { return !(*this == other); }
T &operator*() { return m_func(m_index); }
T *operator->() { return &m_func(m_index); };
protected:
std::size_t m_index = 0;
access_function_t m_func;
const void *m_id = nullptr;
};
Note that I had to introduce the m_id member variable as a means to properly compare iterators (std::function can't be compared using ==). it is meant to be e.g. the address of the container the elements are contained in. Its sole purpose is to make sure that 2 iterators that happen to have the same index but are iterating over completely different sets are not considered equal.
And based on that here's an implementation of an Iterable<T>:
template< typename T > struct Iterable {
using iterator = iterator_impl< T >;
using const_iterator = iterator_impl< const std::remove_const_t< T > >;
Iterable(std::size_t start, std::size_t end, typename iterator_impl< T >::access_function_t &func, const void *id)
: m_begin(start, func, id), m_end(end, func, id) {}
iterator begin() { return m_begin; }
iterator end() { return m_end; }
const_iterator begin() const { return m_begin; }
const_iterator end() const { return m_end; }
const_iterator cbegin() const { return m_begin; }
const_iterator cend() const { return m_end; }
protected:
iterator m_begin;
iterator m_end;
};
I want to access my iterator class by reference
#include <iostream>
template <typename T> class binary_tree;
template <typename T>
class binary_tree_iterator {
private:
binary_tree<T>* tree;
T data;
public:
binary_tree_iterator(binary_tree<T>* t) : tree(t) {}
T& operator*() {data = tree->data(); return data;}
binary_tree_iterator& operator++() {tree = tree->get_node(); return *this;}
bool operator!=(binary_tree_iterator& rhs) {return tree->data() != rhs.tree->data();}
};
template <typename T>
class binary_tree {
private:
T t_data;
binary_tree<T>* node;
binary_tree_iterator<T>* It;
public:
binary_tree(T d) : t_data(d), node(nullptr), It(nullptr)
{}
T& data() {
return t_data;
}
void set_node(binary_tree<T>* node) {
this->node = node;
}
binary_tree<T>* get_node() {
return node;
}
binary_tree_iterator<T> begin() {
It = new binary_tree_iterator<T>(this);
return *It;
}
binary_tree_iterator<T> end() {
if(node == nullptr) {
It = new binary_tree_iterator<T>(this);
return *It;
} else {
return node->end();
}
}
};
int main() {
binary_tree<int>* tree = new binary_tree<int>(2);
tree->set_node(new binary_tree<int>(3));
//for(auto& x: *tree) <--- does not work
for(auto x: *tree) {
std::cout << x << std::endl;
}
}
The for-range loop I want to use it in looks something like for(auto& x: *tree). How do I give it a reference? Is there a standard way of doing this when creating iterators? When I return the data value I assign it to a iterator data member so I can return by reference. Will I have to do the same with my iterator? I don't imagine this is the standard way of doing this.
I want to access my iterator class by reference
How do I give it a reference?
By changing the return type of the function to be binary_tree_iterator<T>& instead of binary_tree_iterator<T>. If you do that, you'd have to store an iterator somewhere instead of returning a new one, so that you can refer to it. Presumably, it would have to be stored as a member variable.
Is there a standard way of doing this when creating iterators?
No. None of the standard containers return references to iterators.
I don't imagine this is the standard way of doing this.
Indeed. The "standard" i.e. conventional thing to do is to not return references to iterators.
The for-range loop I want to use it in looks something like for(auto& x: *tree)
There is no need to return a reference to an iterator in order to make that work. If you take a look at standard containers, you'll find that none of them return a reference to an iterator, and such loop works with all of them.
The reference in that loop is bound to the result of indirection through the iterator. So, it is the operator* that must return a reference to the pointed object. And, your operator* does indeed return a reference. That said, normally an iterator would return a reference to the object stored in the container; not a reference to copy stored in the iterator. So, that's highly unconventional.
Finish writing your iterator, and you'll find that the loop works.
In conclusion: You don't need to return iterator by reference, and you shouldn't.
I have two classes for example
struct point{
dint data
};
class data{
...
public:
point left;
point right;
..... //more that 50 members of point
point some_other_point;
}example;
Is it possible use something like "for each point in example" in this situation?
Because now I need to modify many functions if I add one more point to data.
Or maybe, there is any other idea about it.
No, you cannot enumerate members of a type, because C++ does not have the concept of reflection.
This is a common use case for an array, a vector or a map.
Yes, and there are two ways to do so:
an iterator class, for external iteration
a visitation method, for internal iteration
Then the iteration logic is encapsulated in either of those classes and all the code just uses them.
Using the iterator class.
Pros:
can easily be combined with existing STL algorithms, as well as for and while loops
can suspend (and resume) iteration
Cons:
requires polymorphism of attributes iterated over
Example:
class DataIterator;
class Data {
public:
friend class DataIterator;
Data(Point a, Point b, Point c): _one(a), _two(b), _three(c) {}
DataIterator begin();
DataIterator end();
private:
Point _one;
Point _two;
Point _three;
}; // class Data
class DataIterator:
public std::iterator<std::forward_iterator_tag, Point>
{
public:
struct BeginTag{};
struct EndTag{};
DataIterator(): _data(0), _member(0) {}
DataIterator(Data& data, BeginTag): _data(&data), _member(0) {}
DataIterator(Data& data, EndTag): _data(&data), _member(N) {}
reference operator*() const {
this->ensure_valid();
MemberPtr const ptr = Pointers[_member];
return _data->*ptr;
}
pointer operator->() const { return std::addressof(*(*this)); }
DataIterator& operator++() { this->ensure_valid(); ++_member; return *this; }
DataIterator operator++(int) { DataIterator tmp(*this); ++*this; return tmp; }
friend bool operator==(DataIterator const& left, DataIterator const& right) {
return left._data == right._data and left._member == right._member;
}
friend bool operator!=(DataIterator const& left, DataIterator const& right) {
return not (left == right);
}
private:
typedef Point Data::*MemberPtr;
static size_t const N = 3;
static MemberPtr const Pointers[N];
void ensure_valid() const { assert(_data and _member < N); }
Data* _data;
size_t _member;
}; // class DataIterator
//
// Implementation
//
DataIterator Data::begin() { return DataIterator(*this, DataIterator::BeginTag{}); }
DataIterator Data::end() { return DataIterator(*this, DataIterator::EndTag{}); }
size_t const DataIterator::N;
DataIterator::MemberPtr const DataIterator::Pointers[DataIterator::N] = {
&Data::_one, &Data::_two, &Data::_three
};
And in case you wonder: yes, it really works.
Using the visitation method, though, is easier.
Pros:
can easily accommodate variance in the attributes types iterated over
Cons:
cannot be combined with existing STL algorithms or existing loops
pretty difficult to suspend the iteration part-way
Example:
class Data {
public:
Data(Point a, Point b, Point c): _one(a), _two(b), _three(c) {}
template <typename F>
void apply(F&& f) {
f(_one);
f(_two);
f(_three);
}
private:
Point _one;
Point _two;
Point _three;
}; // class Data
And of course, it works too.
Do it like this:
class data{
public:
enum POINTS {LEFT=0,RIGHT,SOME_OTHER_POINT};
std::array<point,50> points; // or just point points[50];
}example;
And use it like this:
example.points[data::LEFT]=point{};
Then you can iterate over points array with standard techniques.
You can convert your current fields into:
private:
point left;
// ..
public:
point& left() { return points[LEFT]; }
// ..
where points might be an array of points (as in other answers), and LEFT is a constant index into array. This should allow for a relatively quick and painless transition, you will only have to add (), and compiler will output errors where to apply fixes.
Then you can convert your code to iterate your point values.
You can write a for each function without modifying your example like this:
template<class Func>
void for_each_point(example& e, Func&& f){
f(e.pt1);
f(e.pt2);
f(e.blah);
....
f(e.last_pt);
}
and then call it like:
for_each_point(exam, [&](point & pt){
std::cout<<pt.data<<"\n";
});
or do whatever in the body.
This function could also be a member variable, if you prefer.
Changing tye point storage to an array or std::array amd exposing begin and end or the array also works.
Finally, you could write a custom iterator that walks the points, but that is probably unwise.
I'm trying to implement erase function to my square list function but when I write mine it give me this compiler error
Error 1 error C2664: 'square_list::erase' : cannot convert
parameter 1 from 'std::_List_iterator<_Mylist>' to 'int *'
main code
#define nullptr NULL
template <typename T_>
class square_list
{
void erase(iterator it)
{
data.erase(it);
}
};
std::list<T>::erase takes a list::iterator as argument, but you are trying to pass it a square_list<T>::iterator, a.k.a. a T*.
I would question the logic of defining iterators as T* for a squared_list<T>, while simultaneously exposing list<T>::iterators to the underlying list in the public interface (begin() and `end()1), as this breaks encapsulation.
Nevertheless, if you want to proceed, you can do something like this:
void erase(typename std::list<T>::iterator it)
{
data.erase(it);
}
Or, if you want to actually use the iterators that you define in your squared_list class:
void erase(iterator it)
{
// look for the underlying list iterator pointing to this value
auto underlyingIt = std::find_if(data.begin(), data.end(), [=](const T& node) {
return (&node == it);
});
if (underlyingIt != data.end()) {
data.erase(underlyingIt);
} else {
// handle case where the "iterator" is not found here
}
}
Make the erase function to take the std::list iterator, as follows:
void erase(typename std::list<value_type>::iterator it)
{
data.erase(it);
}
Live example: http://ideone.com/c3T9Hs
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () const {
return &(Enum::OfInt(i)); // warning: taking address of temporary
}
const Enum operator* () const {
return Enum::OfInt(i); // There is no problem with this one!
}
private:
int i;
};
I get this warning above. Currently I'm using this hack:
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
private:
int i;
Enum tmp;
};
But this is ugly because iterator serves as a missing container.
What is the proper way to iterate over range of values?
Update:
The iterator is specialized to a particular set objects which support named static constructor OfInt (code snippet updated).
Please do not nit-pick about the code I pasted, but just ask for clarification. I tried to extract a simple piece.
If you want to know T will be strong enum type (essentially an int packed into a class). There will be typedef EnumIterator < EnumX > Iterator; inside class EnumX.
Update 2:
consts added to indicate that members of strong enum class that will be accessed through -> do not change the returned temporary enum.
Updated the code with operator* which gives no problem.
Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
The problem with this isn't that it's ugly, but that its not safe. What happens, for example in code like the following:
void f(EnumIterator it)
{
g(*it, *it);
}
Now g() ends up with two pointers, both of which point to the same internal temporary that was supposed to be an implementation detail of your iterator. If g() writes through one pointer, the other value changes, too. Ouch.
Your problem is, that this function is supposed to return a pointer, but you have no object to point to. No matter what, you will have to fix this.
I see two possibilities:
Since this thing seems to wrap an enum, and enumeration types have no members, that operator-> is useless anyway (it won't be instantiated unless called, and it cannot be called as this would result in a compile-time error) and can safely be omitted.
Store an object of the right type (something like Enum::enum_type) inside the iterator, and cast it to/from int only if you want to perform integer-like operations (e.g., increment) on it.
There are many kind of iterators.
On a vector for example, iterators are usually plain pointers:
template <class T>
class Iterator
{
public:
T* operator->() { return m_pointer; }
private:
T* m_pointer;
};
But this works because a vector is just an array, in fact.
On a doubly-linked list, it would be different, the list would be composed of nodes.
template <class T>
struct Node
{
Node* m_prev;
Node* m_next;
T m_value;
};
template <class T>
class Iterator
{
public:
T* operator->() { return m_node->m_value; }
private:
Node<T>* m_node;
};
Usually, you want you iterator to be as light as possible, because they are passed around by value, so a pointer into the underlying container makes sense.
You might want to add extra debugging capabilities:
possibility to invalidate the iterator
range checking possibility
container checking (ie, checking when comparing 2 iterators that they refer to the same container to begin with)
But those are niceties, and to begin with, this is a bit more complicated.
Note also Boost.Iterator which helps with the boiler-plate code.
EDIT: (update 1 and 2 grouped)
In your case, it's fine if your iterator is just an int, you don't need more. In fact for you strong enum you don't even need an iterator, you just need operator++ and operator-- :)
The point of having a reference to the container is usually to implement those ++ and -- operators. But from your element, just having an int (assuming it's large enough), and a way to get to the previous and next values is sufficient.
It would be easier though, if you had a static vector then you could simply reuse a vector iterator.
An iterator iterates on a specific container. The implementation depends on what kind of container it is. The pointer you return should point to a member of that container. You don't need to copy it, but you do need to keep track of what container you're iterating on, and where you're at (e.g. index for a vector) presumably initialized in the iterator's constructor. Or just use the STL.
What does OfInt return? It appears to be returning the wrong type in this case. It should be returning a T* instead it seems to be returning a T by value which you are then taking the address of. This may produce incorrect behavior since it will loose any update made through ->.
As there is no container I settled on merging iterator into my strong Enum.
I init raw int to -1 to support empty enums (limit == 0) and be able to use regular for loop with TryInc.
Here is the code:
template <uint limit>
class Enum {
public:
static const uint kLimit = limit;
Enum () : raw (-1) {
}
bool TryInc () {
if (raw+1 < kLimit) {
raw += 1;
return true;
}
return false;
}
uint GetRaw() const {
return raw;
}
void SetRaw (uint raw) {
this->raw = raw;
}
static Enum OfRaw (uint raw) {
return Enum (raw);
}
bool operator == (const Enum& other) const {
return this->raw == other.raw;
}
bool operator != (const Enum& other) const {
return this->raw != other.raw;
}
protected:
explicit Enum (uint raw) : raw (raw) {
}
private:
uint raw;
};
The usage:
class Color : public Enum <10> {
public:
static const Color red;
// constructors should be automatically forwarded ...
Color () : Enum<10> () {
}
private:
Color (uint raw) : Enum<10> (raw) {
}
};
const Color Color::red = Color(0);
int main() {
Color red = Color::red;
for (Color c; c.TryInc();) {
std::cout << c.GetRaw() << std::endl;
}
}