How to control value assigned by operator [] - c++

I know how to overload operator[] as follows :
T& operator [](int idx) {
return TheArray[idx];
}
T operator [](int idx) const {
return TheArray[idx];
}
But what I want is to control values assigned by arr[i] = value.
I want to control value to be between 0 and 9.
Is there any syntax to do so?

You would have to write a template class that holds a reference to the element in the array (of type T), in this template you implement the assignment operator, and there you can implement your check. Then you return an object of this template class from your [] operator.
Something like this:
template< typename T> class RangeCheck
{
public:
RangeCheck( T& dest): mDestVar( dest) { }
RangeCheck& operator =( const T& new_value) {
if ((0 <= new_value) && (new_value < 9)) { // <= ??
mDestVar = new_value;
} else {
... // error handling
}
return *this;
}
private:
T& mDestVar;
};

Rene has provided a good answer. In addition to this, here is a full example. Note that I added a "user-defined conversion", i.e., operator T, in the proxy_T class.
#include <iostream>
#include <array>
#include <stdexcept>
template <class T>
class myClass
{
std::array<T, 5> TheArray; // Some array...
class proxy_T
{
T& value; // Reference to the element to be modified
public:
proxy_T(T& v) : value(v) {}
proxy_T& operator=(T const& i)
{
if (i >= 0 and i <= 9)
{
value = i;
}
else
{
throw std::range_error(std::to_string(i));
}
return *this;
}
operator T() // This is required for getting a T value from a proxy_T, which make the cout-lines work
{
return value;
}
};
public:
proxy_T operator [](int const idx)
{
return TheArray.at(idx);
}
T operator [](int const idx) const
{
return TheArray[idx];
}
};
int main() {
myClass<int> A;
std::cout << A[0] << std::endl;
A[0] = 2;
std::cout << A[0] << std::endl;
A[1] = 20;
}

Related

Handling custom vector classes

I have come across many occasions where I want to have an item which is selected inside a vector, for this I have written the template class:
// a vector wrapper which allows a specific item to be currently selected
template<typename T>
class VectorSelectable
{
public:
VectorSelectable() {};
VectorSelectable(std::initializer_list<T> items) : m_Items(items) {};
void Add(const T& v) { m_Items.push_back(v); m_CurrentIndex = m_Items.size()-1; } // lvalue & refs
void Add(T&& v) { m_Items.push_back(std::move(v)); m_CurrentIndex = m_Items.size()-1; } // rvalue
void Remove(size_t index) {
assert(index < m_Items.size());
m_Items.erase(m_Items.begin() + index);
if(m_CurrentIndex != -1 && (int)index <= m_CurrentIndex)
m_CurrentIndex--;
}
void RemoveCurrent() { assert(m_CurrentIndex > -1 && m_CurrentIndex < (int)m_Items.size()); Remove(m_CurrentIndex); }
T& CurrentItem() { assert(m_CurrentIndex > -1 && m_CurrentIndex < (int)m_Items.size()); return m_Items[m_CurrentIndex]; }
T& operator [](size_t index) { assert(index < Size()); return m_Items[index]; }
// moves value of n_next onto n, and n_new onto n
void ItemSwap(size_t n, size_t n_Next) {
assert(n < m_Items.size());
assert(n_Next < m_Items.size());
T itemBuf = std::move(m_Items[n]);
m_Items[n] = m_Items[n_Next];
m_Items[n_Next] = std::move(itemBuf);
}
size_t Size() { return m_Items.size(); }
const std::vector<T>& Data() { return m_Items; }
std::vector<T>* DataPtr() { return &m_Items; }
T* ItemPtr(size_t index) { assert(index < m_Items.size()); return &m_Items[index]; }
void SetCurrentIndex(int index) { assert(index >= -1 && index < (int)m_Items.size()); m_CurrentIndex = index; }
int& CurrentIndex() { return m_CurrentIndex; }
bool HasItemSelected() { return m_CurrentIndex != -1; }
private:
std::vector<T> m_Items;
int m_CurrentIndex = -1;
};
I am also coming across many scenarios where I want a vector of unique_ptrs (generally for polymorphic classes), this looks like this:
template<typename T>
class Vector_UniquePtrs
{
public:
// Adds an Item (and returns a raw ptr to it)
// usage: v.Add() ... (equivelent to v.Add<base_class>())
template<typename... Args>
T* Add(Args... args) {
return Add<T>(args...);
}
// Adds a Polymorphic Item (and returns a raw ptr to it)
// usage: v.Add<sub_class>()
template<typename T2, typename... Args>
T* Add(Args... args) {
m_Items.push_back(std::unique_ptr<T>(new T2(args...)));
return m_Items.back().get();
}
// Remove Item
void Remove(size_t index) {
assert(index < m_Items.size());
m_Items.erase(m_Items.begin() + index);
}
T* operator [](size_t index) { assert(index < Size()); return m_Items[index].get(); }
size_t Size() { return m_Items.size(); }
private:
std::vector<std::unique_ptr<T>> m_Items;
};
My question is:
How can I handle a combination of these 2 class types (e.g. VectorSelectable<unique_ptr>) as one returns ptrs, the other returns references, is the only option to write an entirely new class?
You mainly need to put the std::vector<std::unique_ptr<T>> in VectorSelectable and hide all the pointer stuff from the interface. With a few small changes to your class, it could look like this:
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
template <typename T>
class VectorPtrSelectable {
public:
VectorPtrSelectable() = default;
VectorPtrSelectable(std::initializer_list<T> items) :
m_CurrentIndex(items.size() - 1)
{
m_Items.reserve(items.size());
// fill `m_Items` from the initializer list ...
std::transform(items.begin(), items.end(), std::back_inserter(m_Items),
[](const T& item) {
// ... by creating a unique_ptr from each element (transformation)
return std::make_unique<T>(item);
});
};
template <class U, class... Args>
T& Add(Args&&... args) {
// make `Add` forward to `make_unique`
m_Items.emplace_back(std::make_unique<U>(std::forward<Args>(args)...));
m_CurrentIndex = m_Items.size() - 1;
// and return a reference instead
return *m_Items.back();
}
template <class... Args>
T& Add(Args&&... args) {
// forward to Add<U>
return Add<T>(std::forward<Args>(args)...);
}
void Remove(size_t index) {
m_Items.erase(std::next(m_Items.begin(), index));
if (m_CurrentIndex != static_cast<size_t>(-1) && index <= m_CurrentIndex)
m_CurrentIndex--;
}
T& operator[](size_t index) { return *m_Items[index]; }
const T& operator[](size_t index) const { return *m_Items[index]; }
T& CurrentItem() { return *m_Items[m_CurrentIndex]; }
const T& CurrentItem() const { return *m_Items[m_CurrentIndex]; }
void SetCurrentIndex(size_t index) { m_CurrentIndex = index; }
void RemoveCurrent() { Remove(m_CurrentIndex); }
bool HasItemSelected() { return m_CurrentIndex != static_cast<size_t>(-1); }
void ItemSwap(size_t n, size_t n_Next) {
// simplified swapping:
std::swap(m_Items[n], m_Items[n_Next]);
}
// make functions that does not change your instance const qualified:
size_t CurrentIndex() const { return m_CurrentIndex; }
size_t Size() const { return m_Items.size(); }
private:
std::vector<std::unique_ptr<T>> m_Items;
size_t m_CurrentIndex = static_cast<size_t>(-1); // size_t for the index
};
Example usage:
#include <iostream>
#include <string>
int main() {
VectorPtrSelectable<std::string> vs{"World", "Hello"};
std::cout << vs.CurrentItem() << '\n';
vs.ItemSwap(0, 1);
std::cout << vs.CurrentItem() << '\n';
vs.RemoveCurrent();
std::cout << vs.CurrentItem() << '\n';
std::cout << vs.Add("Add and get a reference") << '\n';
}
Output:
Hello
World
Hello
Add and get a reference
I made m_CurrentIndex a size_t because that's idiomatic but if you'd like to keep it as an int, that's fine too.
std::next(m_Items.begin(), index) will do the same as m_Items.begin() + index, but in cases where the iterator returned by m_Items.begin() is a plain pointer, using std::next avoids potential warnings about using pointer arithmetic.
Returning a reference instead of a pointer to the added element makes no difference other than making the interface more idiomatic. It's simply what a user of the class is likely to expect. Returning a pointer also opens up questions like "can it return nullptr?" etc.
The added const qualified functions makes those functions usable in const contexts too.
template<class T>
void foo(const VectorPtrSelectable<T>& vps) { // note: const&
if(vps.Size() > 0) {
std::cout << "the first element is " << vps[0] << '\n';
std::cout << "the current element is " << vps.CurrentItem() << '\n';
}
}
None of the three member functions used above could be used without the const qualified overloads.

2d vector modify with iterator

I have a 2d matrix using vector library. And I wanted to iterate over the Matrix more conveniently, so I created an MatrixIterator class.
Matrix.cpp
#include <vector>
template <class T>
class MatrixIterator;
template <class T>
class Matrix
{
friend class MatrixIterator<T>;
private:
public:
std::vector<std::vector<T>> m;
unsigned rows_;
unsigned cols_;
Matrix<T>(unsigned rows, unsigned cols);
MatrixIterator<T> iterator() const
{
return {*this};
}
MatrixIterator<T> begin() const
{
return {*this};
}
MatrixIterator<T> end() const
{
return {*this, rows_, 0};
}
}
template <class T>
class MatrixIterator
{
private:
Matrix<T> matrix_;
unsigned row_;
unsigned col_;
public:
MatrixIterator<T>(Matrix<T> m) : matrix_(m), row_(0), col_(0) {};
MatrixIterator<T>(Matrix<T> m, unsigned row, unsigned col) : matrix_(m), row_(row), col_(col) {};
MatrixIterator<T> begin() const
{
return {matrix_};
}
MatrixIterator<T> end() const
{
return {matrix_, matrix_.rows_, 0};
}
void inc()
{
if(++col_ >= matrix_.cols_)
{
row_++;
col_ = 0;
}
}
MatrixIterator<T>& operator++()
{
inc();
return *this;
}
MatrixIterator<T> operator++(int)
{
inc();
return *this;
}
bool operator!=(const MatrixIterator<T> &rhs) const
{
return (row_ != rhs.row_) || (col_ != rhs.col_);
}
T& operator*()
{
return matrix_.m[row_][col_];
}
};
template <class T>
Matrix<T>::Matrix(unsigned rows, unsigned cols)
: rows_(rows), cols_(cols)
{
m.resize(cols);
for (unsigned i = 0; i < cols; i++)
{
m[i].resize(rows);
fill(m[i].begin(), m[i].end(), T());
}
}
In the following code, when I try to manipulate value using iterator, it does not change the value.
I tried returning the values as pointers from operator* but it did not work either. I saw no errors. What is wrong and how can I solve this?
main.cpp
#include "Matrix.cpp"
#include<iostream>
int main()
{
Matrix<int> m = Matrix<int>{3,3};
for(auto x: m.iterator())
x = 10;
for(auto x: m.iterator())
std::cout << x << " ";
// outputs 0 0 0 ~
}
Compiled with g++ main.cpp -std=c++20 -g -o main && main
You need to store a reference in the iterator class, other than hold a copy of it (iterator is just a view of the data).
template <class T>
class MatrixIterator {
private:
Matrix<T>& matrix_;
unsigned row_;
unsigned col_;
public:
MatrixIterator<T>(Matrix<T>& m) : MatrixIterator<T>(m, 0, 0) {}
MatrixIterator<T>(Matrix<T>& m, unsigned row, unsigned col)
: matrix_(m), row_(row), col_(col) {}
};
And you also need to non-const begin and end for your matrix, nonconst version iterator can be used to change the underlying value. The function iterator() can be removed here, since it's not common to have this in c++ code.
MatrixIterator<T> begin() const { return {*this}; }
MatrixIterator<T> begin() { return {*this}; }
MatrixIterator<T> end() const { return {*this, rows_, 0}; }
MatrixIterator<T> end() { return {*this, rows_, 0}; }
To change to the value with an iterator, you need a reference other than changing the copied value in your main function. It's not necessary to explicitly call the iterator here, the compiler will do it for you.
int main() {
Matrix<int> m = Matrix<int>{3, 3};
for (auto& x : m) x = 10;
for (auto x : m) std::cout << x << " ";
return 0;
}
Online demo.
You are iterating over values, not references when attempting to change the matrix values. Instead, try
for (auto& x : m.iterator())

c++ subscript operator to underling class vector

So i'm trying to create a vec class that I can do vec math on at a later point.
Was working great until I began Implementing actual procedures on it.
Class vecn:
#include <vector>
template <typename T>
class vecn
{
public:
vecn() { }
template <typename... Args>
vecn(Args&&... args)
{
addtovector(args...);
}
friend std::ostream& operator<<(std::ostream& os, const vecn<T>& obj)
{
os << "{";
for (auto it = obj.contents.begin(); it < obj.contents.end(); it++) {
os << *it;
if (it != obj.contents.end() -1)
{
os << ",";
}
}
os << "}";
return os;
}
template<typename T>
vecn<T>& operator=(const vecn<T>& v) {
contents = v.contents;
return *this;
}
unsigned int size() const
{
return contents.size();
}
vecn<T> operator+(const vecn<T>& v1) {
vecn<T> v2();
for (unsigned int i = 0; i < size();i++)
{
v2[i] = v1[i] + this->contents[i];
}
return v2;
}
T& operator[](size_t Index)
{
if (Index > contents.size() -1)
{
contents.resize(Index + 1);
}
return contents.at(Index);
}
const T& operator[](size_t Index) const
{
return contents.at(Index);
}
private:
template <typename... Args>
void addtovector(T& first, Args&&... args)
{
addtovector(first);
addtovector(args...);
}
void addtovector(T& item)
{
contents.push_back(item);
}
std::vector<T> contents;
};
Now i'm having a problem with acceing the underling vector using the subscript operator, no matter how I design it, it never quite works. Usually resulting in a
Error C2109 subscript requires array or pointer type
From Googling the error, I'm supposed to return a pointer to the array with the subscript. which I do.
Is there something i'm missing?
main:
vecn<int> v(1,2);
vecn<int> b(3, 4, 5);
std::cout << v + b;
Expected output:
{4,6,5}
GCC told me exactly what's wrong:
error: declaration of template parameter ‘T’ shadows template parameter
(for your assignment operator)
Then:
warning: pointer to a function used in arithmetic [-Wpointer-arith]
v2[i] = v1[i] + this->contents[i];
(you've declared v2 as a function returning vecn<T>, remove the parentheses)
Lastly, fix your operator+, because it will try to access elements of an empty v2 vector and access out of range of the smaller of v1 and this->contents if their sizes are not equal.
It seems to me that you have wrote a lot of unnecessary code for such a simple thing. You don't need addtovector, just expand the parameter pack like:
contents{std::forward<Args>(args)...}
in the member initializer list. You don't need to define operator= at all, leave it up to the compiler. And try to implement operator+ in terms of operator+=.
Despite all other things you have one rather creepy thing in your code
if (Index > contents.size() -1)
You should never ever replace the correct choice of the boolean operator by arithmetic operations! std::vector<>.size() returns size_t (unsigned long on most systems), only your selfmade size() returns int, which it shouldn´t since there is no meaning in negative sizes.
Now 0 - 1 doesn´t yield a negative with 0 being size_t but something huuuge: 18446744073709551615 (0xffffffffffffffff).
So with size()=0
if (Index > contents.size() -1)
Will never ever be true and your vec will not grow, as you wanted, on access to vec[0]. Simply use
if (Index >= contents.size())
Which is exactly what you mean.
Likely your problem was that you used vecn<T> v2(); instead of vecn<T> v2;, but there are another bad things in your solution. Here is some refactor:
template <typename T>
class vecn {
public:
vecn() {}
template <typename... Args>
vecn(Args&&... args)
{
addToVector(args...);
}
friend std::ostream& operator<<(std::ostream& os, const vecn<T>& obj)
{
os << "{";
for (auto it = obj.contents.begin(); it < obj.contents.end(); it++) {
os << *it;
if (it != obj.contents.end() - 1)
os << ",";
}
os << "}";
return os;
}
// you don't need this
// template<typename T>
// also whole method is unnecessary
// vecn<T>& operator=(const vecn<T>& v)
// {
// contents = v.contents;
// return *this;
// }
// use size_t
/*unsigned int*/ size_t size() const
{
return contents.size();
}
vecn<T> operator+(const vecn<T>& other) const
{
vecn<T> result;
size_t resultSize = std::max(other.size(), size());
result.contents.reserve(resultSize);
for (size_t i = 0; i < resultSize; ++i) {
T value = {};
if (i < other.size())
value += other.contents[i];
if (i < size())
value += contents[i];
result.contents.push_back(value);
}
return result;
}
T& operator[](size_t index)
{
return contents.at(index);
}
const T& operator[](size_t index) const
{
return contents.at(index);
}
private:
template <typename... Args>
void addToVector(T& first, Args&&... args)
{
addToVector(first);
addToVector(args...);
}
void addToVector(T& item)
{
contents.push_back(item);
}
std::vector<T> contents;
};

Is there a way to have a public member, unmodifiable from outside the class, without accessor wrapper function?

As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++?
Currently all I can think of is some trickery with templates and friend. I'm investigating this now.
Might seem like a stupid question, but I have been surprised by answers here before.
A possible solution can be based on an inner class of which the outer one is a friend, like the following one:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.
There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
I like #skypjack's answer, but would have written it somehow like this:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
Some enable_ifs are missing to really be generic to the core, but the spirit is to make it re-usable and to keep the calls looking like getters.
This is indeed a trickery with friend.
You can use curiously recurring template pattern and friend the super class from within a property class like so:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}

Move semantics in MS C++ vs Clang

After doing some experimentation with move semantics with an array type I created, I am wondering why Microsoft's C++ compiler calls the move constructor when returning from a method by value whilst the Clang compiler elides the copy all together?
Is this correct or incorrect behaviour from Clang? or correct behaviour from Microsoft?
#include <algorithm>
#include <iostream>
template<typename T>
class Array {
public:
template<typename E>
class ArrayIterator {
public:
ArrayIterator(Array<E>& elements, int index) : position_(index), elements_(elements) {
}
T& operator * () {
return elements_[position_];
}
ArrayIterator& operator++ () {
position_++;
return *this;
}
ArrayIterator operator++ (int) {
return ArrayIterator(elements_, ++position_);
}
bool operator != (ArrayIterator const & other) {
return position_ != other.position_;
}
private:
int position_;
Array<E>& elements_;
};
typedef ArrayIterator<T> iterator;
Array();
explicit Array(int size);
~Array();
Array(const Array& other);
Array(Array&& other);
Array<T>& operator = (Array other);
T& operator[](int index);
int size() const;
iterator begin();
iterator end();
private:
void internal_swap(Array& other);
T *elements_;
int length_;
};
template<typename T>
Array<T>::Array() {
length_ = 0;
elements_ = 0;
}
template<typename T>
Array<T>::Array(int size) {
elements_ = new T[size];
length_ = size;
}
template<typename T>
Array<T>::~Array() {
delete[] elements_;
std::cout << "Destroy...." << std::endl;
}
template<typename T>
Array<T>::Array(const Array<T>& other) {
std::cout << "copy ctor" << std::endl;
length_ = other.size();
T *elements = new T[size()];
std::copy(other.elements_, other.elements_ + other.size(), elements);
elements_ = elements;
}
template<typename T>
Array<T>::Array(Array<T>&& other) {
std::cout << "move ctor" << std::endl;
length_ = other.size();
T* oelements = other.elements_;
other.elements_ = 0;
this->elements_ = oelements;
}
template<typename T>
Array<T>& Array<T>::operator = (Array other) {
internal_swap(other);
return *this;
}
template<typename T>
T& Array<T>::operator[](int index) {
return elements_[index];
}
template<typename T>
int Array<T>::size() const {
return length_;
}
template<typename T>
typename Array<T>::iterator Array<T>::begin() {
return iterator(*this, 0);
}
template<typename T>
typename Array<T>::iterator Array<T>::end() {
return iterator(*this, size());
};
template<typename T>
void Array<T>::internal_swap(Array& other){
T* oelements = other.elements_;
other.elements_ = this->elements_;
this->elements_ = oelements;
}
Array<int> get_values(int x);
int main(int argc, const char *argv[]) {
Array<int> a = get_values(2);
for (Array<int>::iterator i = a.begin(); i != a.end(); ++i) {
std::cout << *i << std::endl;
}
return 0;
}
Array<int> get_values(int x) {
Array<int> a(10);
if(x == 1) return a;
for (int i = 0; i <= 9; i++) {
a[i] = 1 + i;
}
return a;
}
Copy elision is one of those rare optimizations where the standard allows different observable behavior (it doesn't fall under the as-if rule), yet isn't undefined behavior.
Whether any copy or move constructor is called or elided in this context is unspecified, and different compilers can behave differently and both be correct.