Reputation: 71
I'm just trying to get C++ down and to do that, I gotta make my own libraries and whatnot. So I'm trying to get the beginnings of my own List template class, exactly like the List class in the JDK. So I've got the template and stuff down, I just wanna know how I would make it so that I could loop through the contents of a list object. This way I can print out the contents of said object. I don't exactly know where to start.
#pragma once
template<typename T> class List {
public:
List() : _size(0), _elements(nullptr) {}
~List() {
if (_elements != nullptr) {
delete[] _elements;
}
}
inline int size() { return _size; }
inline void add(T element) {
_size++;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * (_size - 1));
delete[] _elements;
}
buffer[_size - 1] = element;
_elements = buffer;
}
inline void remove(T element) {
_size--;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * _size);
delete[] _elements;
}
else {
assert(false);
}
_elements = buffer;
}
inline T* getElements() {
return _elements;
}
private:
int _size;
T* _elements;
};
And this is my main Cpp file
#include <cstdio>
#include <string>
#include "List.h"
using namespace std;
int main( int argc, char ** argv )
{
string str = "This is a test!";
List<char> list = breakString(str);
for (char c : list.getElements()) {
}
getchar();
return 0;
}
List<char> breakString(string str) {
List<char> list;
for (char c : str) {
list.add(c);
}
return list;
}
So what I'm trying to figure out is in that for loop, I'm used to it being an enhanced for loop like in Java, and is that the same here in C++? If so, how would I make this object iterable?
I figured I would get a more accurate answer to my question if I asked directly.
Upvotes: 1
Views: 2268
Reputation: 29332
The guidelines for validating the Range-based for
can be found on http://en.cppreference.com/w/cpp/language/range-for
If range_expression is an expression of a class type C that has a member named begin and/or a member named end (regardless of the type or accessibility of such member), then begin_expr is __range.begin() and end_expr is __range.end();
In short, since your data is in a raw array, you should add these public methods to you class List<T>
T* begin() { return _elements;}
T* end() { return _elements + _size;}
And then you can invoke the Range-based for
on the object directly:
for (char c : list)
But you have other issues in your code. One of them (not sure it's the only one) is that breakString
returns an object, but your class is not trivial and it does not define any copy
or move
constructors.
This answer adresses the "main" question as to how the enable the Range-based for
for your class. It just needs two methods begin()
and end()
that return something that looks like an iterator (could be an actual iterator or a pointer to a contiguous memory chunk")
You can test the suggested modifications without using breakString
, like this:
int main( int argc, char ** argv )
{
std::string str = "This is a test!";
List<char> list;
for (char c : "abcdef") { list.add(c); }
for (char c : list) { std::cout << c << "\n"; }
}
And to make it "fully iterable" define you can define a nested class called ierator
..
Upvotes: 2