I have a problem. I need to implement my own methods for begin and end to iterate with for-loop through array. But i'm not so sure how to do it. I write code as below
template <typename T>
class container {
public:
size_t n;
T *p;
container(std::initializer_list<T> L) {
int i = 0;
n = L.size();
p = new T[n];
for(auto element : L) {
p[i] = element;
i++;
}
}
T getArray() {
return *p;
}
T *begin(container<T> &cref);
T *end(container<T> &cref);
~container() { delete[] p; }
T &operator[](size_t k) { return p[k]; }
void info() {
std::cout << "Ilość elementów w tablicy: " << n << "\n";
for(const char& c : p)
{
std::cout << c << std::endl;
}
std::cout << "Typ danych: " << typeid(*p).name() << '\n';
};
size_t length() const { return n; }
};
template <typename T>
T* container<T>::begin(container<T> &cref) {
return cref.getArray()[0];
}
template <typename T>
T* container<T>::end(container<T> &cref) {
return cref.getArray()[0 + cref.length()];
}
int main(int argc, char** argv) {
container<char> Z{'a', 'b', 'c', 'd'};
Z.info();
std::cout << Z.length();
return 0;
}
Can someone tell me how to do it and use iterators with for-loop like this:
for(const char& c : p)
{
std::cout << c << std::endl;
}
T is the element type; p is a pointer to the first array element, and begin and end should not take an argument (you're going to iterate over *this).
You want
T* getArray() { return p; }
and
template <typename T>
T* container<T>::begin() {
return p;
}
template <typename T>
T* container<T>::end() {
return p + length();
}
Related
I have a simple sample which provides:
a struct template:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
a function template:
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
I can use it to skip items in foreach loop of a (i.e) std::vector:
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
}
This works as intended, however I don't really understand the need of the function template (2).
I tried to write the foreach loop as this:
for (auto p : range_t<std::vector::const_iterator>(v.begin()+1, v.end()))
But for this I always got
error: template argument 1 is invalid
This might be a duplicate question, feel free to mark it as duplicate and please let me know the duplicated question which answers to all of these questions:
Why is the template argument invalid here?
(How) can I skip the function template?
How can I create a function template which would work as this:
myskipper would get only v as parameter in the foreach loop:
template<typename T>
range_t<T::const_iterator> myskipper(T c) {
return range_t<T::const_iterator>(c.begin()+1, c.end());
}
...
for (auto p : myskipper(v)) ...
Based on the comments and this article about iterator overflow, here a complete working example:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
template<typename T>
range_t<typename T::iterator> skip(T &c, typename T::size_type skipCount)
{
return range_t<typename T::iterator>(c.begin() + std::min(c.size(), skipCount), c.end());
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : range_t(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : skip(v, 3))
{
std::cout << p << " ";
}
std::cout << std::endl;
}
In the following piece of code, I am iterating through a pointer to an array of pointers to TreeNode objects. Below is my code where I iterate through the array:
TreeNode* childListPointer = *currNode->children;
for (TreeNode* currChild = childListPointer; currChild != NULL; currChild = ++childListPointer) {
std::cout << "Iteration" << endl;
}
And below is the code of my TreeNode struct:
typedef struct TreeNode {
int key;
int val;
bool flag;
int num_children;
TreeNode **children;
} TreeNode;
However, my code keeps getting stuck an infinite loop, even when the length of the array is a small number (e.x. 4 or 5).
Note: The autograder system does not allow me to modify the TreeNode struct.
Your array is a size and count.
int num_children;
TreeNode **children;
Based off that, you can make a simple range adapter for for(:) loops:
template<class It>
struct range {
It s, f;
It begin() const { return s; }
It end() const { return f; }
range(It b, It e):s(b),f(e) {}
range(It b, std::ptrdiff_t count):range(b, b+count) {}
};
now, just:
for(TreeNode* child : range{ currNode->children, currNode->num_children })
{
std::cout << "Iteration" << endl;
}
Prior to c++17 you need a make_range:
template<class It>
range<It> make_range( It b, It e ) { return {b,e}; }
template<class It>
range<It> make_range( It b, std::ptrdiff_t c ) { return {b,c}; }
for(TreeNode* child : make_range( currNode->children, currNode->num_children ))
{
std::cout << "Iteration" << endl;
}
because "deduction guides" where added in c++17.
And you are done. You can now iterate over the children without doing any pointer arithmetic and getting confused.
...
If you are stuck in c++03 you can do:
for (int i = 0; i < currNode->num_children; ++i)
{
TreeNode* child = currNode->children[i];
std::cout << "Iteration" << endl;
}
or
TreeNode** it = currNode->children;
TreeNode** end = it+currNode->num_children;
for (; it != end; ++it)
{
TreeNode* child = *it;
std::cout << "Iteration" << endl;
}
which is almost exactly what the range version compiles down to.
I need to build a sort of stack where I can push values on top:
5 // (size 1)
5 3 // (size 2)
5 3 8 // (size 3)
than remove them by value, such as removing 3:
5 8 // (size 2)
than be able to always get the last value (i.e. 8 in the example), when I need it).
I can push max 32 values, so I know the whole size (avoiding heap?).
I think to std::vector with:
initial reserve(32)
.push_back() for insert
vector.erase(std::remove(vector.begin(), vector.end(), value), vector.end()) for remove by value
vector[vector.size() - 1] to retrieve the last element
But maybe there are some stl container better for this kind of process? Not sure if vector are always in the stack and will do further memory reallocation under the hood...
You can write an allocator that contains your 32 values, and refuses to allocate any amount other than 32
template <typename T, std::size_t N = 32>
struct static_allocator
{
T* allocate(std::size_t n) { if (n != N) throw std::bad_alloc(); return arr; }
void deallocate(T *, std::size_t) {}
using pointer = T*;
using const_pointer = const T*;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
template <typename U>
struct rebind
{
using other = static_allocator<U, N>;
};
static_allocator select_on_container_copy_construction() { return {}; }
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
private:
T arr[N];
};
Then a std::vector<T, static_allocator<T>> will have it's elements as subobjects.
I don't think it's possible to avoid dynamic allocation and have sublinear random-access remove.
if size is limited to 32 elements
why not use a circular buffer of 32 elements, and roll the elements when they are 32 ?
There may be some bugs (don't use last() or remove () on an empty container, don't remove an element not inserted...) ,but it works for the functions you wanted. Here is the idea (heap is avoided)
#include <iostream>
template <typename T>
class Container {
public :
static const int smax_ = 32;
void erase () {
T* pt ((T*) val_);
for (int i (0); i != smax_; ++i, ++pt) *pt = 0;
size_ = 0;
}
Container () : size_ (0) { erase ();}
~Container () {}
void copy (const Container& c) {
size_ = c.size_;
T* pt ((T*) val_);
const T* qt ((const T*) c.val_);
for (int i (0); i != size_; ++i, ++pt, ++qt) *pt++ = *qt++;
}
Container (const Container& c) {
copy (c);
}
void push_back (const T& t) {
if (size_ == smax_) {
T* pt ((T*) val_);
const T* qt ((const T*) val_);
++qt;
for (int i (0); i != size_ -1; ++i, ++pt, ++qt) {
*pt = *qt;
}
*pt = t;
}
else {
val_ [size_] = t;
++size_;
}
}
int size () const {
return size_;
}
void remove (const T& t) {
if (!size_) return;
int i (0);
T* pt ((T*)val_);
while ((i < smax_) && (*pt != t)) {
++pt; ++i;
}
if (i != smax_) {
T* qt (pt);
++qt;
for (; i != size_ -1; ++i, ++pt, ++qt) {
*pt = *qt;
}
}
--size_;
}
void write (std::ostream& os) const {
const T* pt ((const T*) val_);
for (int i (0); i != size_; ++i, ++pt) os << *pt << " ";
}
bool operator == (const Container& c) const {
if (size_ != c.size_) return false;
const T* pt ((const T*) val_), *qt ((const T*) c.val_);
for (int i (0); i != size_; ++i, ++pt, ++qt) if (*pt != *qt) return false;
return true;
}
bool operator != (const Container& c) const {
return !operator == (c);
}
T& operator = (const Container& c) {
copy (c);
return *this;
}
T last () const {
return val_ [size_ -1];
}
T val_ [smax_];
int size_;
};
Test Program
int main (int argc, char* argv []) {
Container<int> c;
std::cout << "pushing back 5..." << std::endl;
c.push_back (5);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "pushing back 3..." << std::endl;
c.push_back (3);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "pushing back 8..." << std::endl;
c.push_back (8);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "erasing 3..." << std::endl;
c.remove (3);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
}
and the results :
pushing back 5...
5
c.last == 5
pushing back 3...
5 3
c.last == 3
pushing back 8...
5 3 8
c.last == 8
erasing 3...
5 8
c.last == 8
if you dont want memory reallocation then you can also use list container i.e linked list ..as it has mostly same properties to the vector..just it do not support random access or []operator ...else vector is perfect:)
I can not get the idea of how to create Array template class properly in C++.
The problem is solely out of learning purposes.
Let me provide the code first.
Array.h :
//Developed by Trofimov Yaroslav on 30.03.2018
#ifndef _ARRAY_H_TROFIMOV_
#define _ARRAY_H_TROFIMOV_
#include <string>
template<const size_t n, typename T>
class Array {
static unsigned __freeId, __quantity;
unsigned _id;
T** _array;
const size_t _n;
public:
typedef const bool (* const BooleanResultDelegate)(const T&);
class ArrayError {
const std::string _reason;
const size_t _index;
const size_t _maxIndex;
public:
ArrayError(const size_t index, const size_t maxIndex,const std::string& reason = "")
: _index(index), _maxIndex(maxIndex), _reason(reason) {}
std::string explanation(void) {
std::string res += "Index: " + std::to_string(_index) + "\n";
res += "Max index: " + std::to_string(_maxIndex) + "\n";
res += "Reason: " + _reason + "\n";
return res;
}
};
explicit Array<n, T>(T* arrayFiller = 0)
: _n(n), _array(new T*[n]), _id(++__freeId) {
if(arrayFiller != 0) {
for(size_t i(0); i < length(); ++i) {
_array[i] = new T(*arrayFiller);
}
} else {
for(size_t i(0); i < length(); ++i) {
_array[i] = arrayFiller;
}
}
reportIfDebug<n, T>(*this, "created");
++__quantity;
}
explicit Array<n, T>(const T& arrayFiller)
: _n(n), _array(new T*[n]), _id(++__freeId) {
for(size_t i(0); i < length(); ++i) {
_array[i] = new T(arrayFiller);
}
reportIfDebug<n, T>(*this, "created");
++__quantity;
}
Array<n, T>(const Array<n, T>& that)
: _n(n), _array(new T[n]), _id(++__freeId) {
for(size_t i(0); i < length(); ++i) {
(*this)[i] = new T[that[i]];
}
reportIfDebug<n, T>(*this, "created");
++__quantity;
}
~Array<n, T>(void) {
removeAll();
delete [] _array; _array = 0;
reportIfDebug<n, T>(*this, "deleted", false);
--__quantity;
}
T* operator[](const size_t i) {
if(i > length()) {
throw ArrayError(i, _n, "out of bounds exception");
}
return _array[i];
}
const T* operator[](const size_t i) const {
if(i > length()) {
throw ArrayError(i, _n, "out of bounds exception");
}
return _array[i];
}
const size_t length() const {
return _n;
}
const unsigned getID() const {
return _id;
}
void removeAll(BooleanResultDelegate removeCondition = 0) {
for(size_t i(0); i < length(); ++i) {
if(removeCondition == 0 || removeCondition(*_array[i])) {
delete [] _array[i]; _array[i] = 0;
}
}
}
};
template<const size_t n, typename T>
unsigned Array<n, T>::__freeId(0);
template<const size_t n, typename T>
unsigned Array<n, T>::__quantity(0);
template<const size_t n, typename T>
void reportIfDebug(
const Array<n, T>& instance,
const char* const message,
const bool showContent = true) {
#ifndef NDEBUG
std::cout << "========================================" << std::endl;
std::cout << typeid(instance).name() << ' '
<< message << ' '
<< "id: " << instance.getID() << std::endl;
if(showContent) {
std::cout << instance;
}
std::cout << "========================================" << std::endl;
#endif
}
template<const size_t n, typename T>
std::ostream& operator<<(std::ostream& os, const Array<n, T>& instance) {
for(size_t i(0); i < instance.length(); ++i) {
if(instance[i] == 0) {
os << "[" << i << "]: " << instance[i] << "\n";
} else {
os << "[" << i << "]: " << *instance[i] << "\n";
}
}
return os;
}
#endif
Main.cpp :
//Developed by Trofimov Yaroslav on 30.03.2018
#include <iostream>
#include "Array.h"
int main(void) {
const Array<5, int> a(7);
std::cout << *a[2] << std::endl;
return 0;
}
What is the main problem right now - is that the client of my Array class would have to use [indirection operator *] and [0 value pointer check] to use the objects from array.
I do not want the client to do that. But, if I use reference instead of pointer as a return type of operator[] I will not be able to return types which do not have copy constructor and I will return trash if nothing was put there before.
It seems like in Java and C# the problem is not fixed as well. The user is getting a reference to an object there and definitely should check for null being returned. And [indirection operator *] is called automatically there.
I am still kind of new to C++ and am trying to figure out what I am not able to pass a value correctly to a bitset, at least I suspect that is what the problem is.
I wrote a small function to assist in flipping the bits of a hex value to reverse the endian. So example would be input 0x01 and it would return 0x80.
This is the code I wrote.
int flipBits(char msd, char lsd) {
char ch[5];
sprintf_s(ch, "0x%d%d", msd, lsd);
char buffer[5];
strncpy_s(buffer, ch, 4);
cout << ch << endl;
cout << buffer << endl;
bitset<8> x(buffer);
bitset<8> y;
for (int i = 0; i < 8; i++) {
y[i] = x[7 - i];
}
cout << y << endl; // print the reversed bit order
int b = y.to_ulong(); // convert the binary to int
cout << b << endl; // print the int
cout << hex << b << endl; // print the hex
return b;
}
I tried adding the strncpy because I thought maybe the null terminator from sprintf was not working properly with the bitset. If in the line
bitset<8> x(buffer);
I replace buffer with a hex value, say for example 0x01, then it works and prints out 0x80 as I would expect, but if I try to pass in the value with the buffer it doesn't work.
We can write a stl-like container wrapper such that we can write:
int main() {
std::bitset<8> x(0x01);
auto container = make_bit_range(x);
std::reverse(container.begin(), container.end());
std::cout << x << std::endl;
}
and expect the output:
10000000
full code:
#include <iostream>
#include <bitset>
#include <algorithm>
template<std::size_t N>
struct bit_reference {
bit_reference(std::bitset<N>& data, int i) : data_(data), i_(i) {}
operator bool() const { return data_[i_]; }
bit_reference& operator=(bool x) {
data_[i_] = x;
return *this;
}
std::bitset<N>& data_;
int i_;
};
template<std::size_t N>
void swap(bit_reference<N> l, bit_reference<N> r) {
auto lv = bool(l);
auto rv = bool(r);
std::swap(lv, rv);
l = lv;
r = rv;
}
template<std::size_t N>
struct bit_range {
using bitset_type = std::bitset<N>;
bit_range(bitset_type &data) : data_(data) {}
struct iterator {
using iterator_category = std::bidirectional_iterator_tag;
using value_type = bit_reference<N>;
using difference_type = int;
using pointer = value_type *;
using reference = value_type &;
iterator(bitset_type &data, int i) : data_(data), i_(i) {}
bool operator==(iterator const &r) const { return i_ == r.i_; }
bool operator!=(iterator const &r) const { return i_ != r.i_; }
iterator &operator--() {
return update(i_ - 1);
}
iterator &operator++() {
return update(i_ + 1);
}
value_type operator*() const {
return bit_reference<N>(data_, i_);
}
private:
auto update(int pos) -> iterator & {
i_ = pos;
return *this;
}
private:
bitset_type &data_;
int i_;
};
auto begin() const { return iterator(data_, 0); }
auto end() const { return iterator(data_, int(data_.size())); }
private:
bitset_type &data_;
};
template<std::size_t N>
auto make_bit_range(std::bitset<N> &data) {
return bit_range<N>(data);
}
int main() {
std::bitset<8> x(0x01);
auto container = make_bit_range(x);
std::reverse(container.begin(), container.end());
std::cout << x << std::endl;
}
also plenty of fun algorithms here: Best Algorithm for Bit Reversal ( from MSB->LSB to LSB->MSB) in C