I have a uni assignment in which I have to create a custom template which acts as an array of doubles. It also has to implement a sorting algorithm which sorts the elements in descending order. I designed the template so it has an internal array of doubles with the length declared by the user (MyArray<10> contains a double array with a length of 10). My custom array will only be filled up with doubles in ascending order from myArr[0] and values won't be changed once assigned, but they can be any value so I can't have a magic constant to keep track of them. Instead I have to check the number of assignments to the array so when I call the sort() method, it knows which is the last changed element.
My subscript operator:
Proxy &operator[](int elem) {
if(elem > arr_size - 1) {
throw std::out_of_range("Out of range");
}
std::cout << "a" << std::endl;
return Proxy(*this, elem);
}
And the proxy class which is inside the F8 class:
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
};
Is there a way to check if operator[] is in an assignment (or if it is an lvalue)? I have tried it with a proxy class but it just seems too complicated for a beginner C++ class and that way I have to implement all of the operators (the values get compared etc, so when with operator[] I return a double it can be compared directly, but when I return the Proxy class, the compiler gives an error for every operator because they don't exist, and the task doesn't ask me to implement all the operators needed for comparison).
Thank you for your time!
Edit: I get the following error when I try to return a proxy class in which I can keep track of the assignment operator:
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'F8<433>::Proxy')
Also to make things clear: the array will be filled in the ascending order of indexes, so after I assign a value to myArr[0] comes myArr[1].
I seems to me like you are looking for a user defined conversion.
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
operator int() const { return a.arr[id]; }
// ^ int or double? You say double but your example code seems to be using int.
};
Not sure how/what your assignment operator is supposed to do. Right now it's only returning a value from your array but not actually assigning anything.
What about something like
int& operator=(int x) { curr_num++; a.arr[id]=x; return a.arr[id]; }
Related
I have a project that wants me to make a BigNum class in c++ (university project)
and it said to overload operator bracket for get and set
but the problem is if the set was invalid we should throw an exception the invalid is like
BigNum a;
a[i]=11;//it is invalid because its >9
in searching I found out how to make the set work
C++ : Overload bracket operators [] to get and set
but I didn't find out how to manage setting operation in c# you easily can manage the set value what is the equivalent of it in c++
to make it clear in C# we can say
public int this[int key]
{
set
{
if(value<0||value>9)throw new Exception();
SetValue(key,value);
}
}
New Answer
I have to rewrite my answer, my old answer is a disaster.
The check should happen during the assignment, when the right hand side (11) is available. So the operator which you need to overload is operator=. For overloading operator=, at least one of its operands must be an user defined type. In this case, the only choice is the left hand side.
The left hand side we have here is the expression a[i]. The type of this expression, a.k.a the return type of operator[], must be an user defined type, say BigNumberElement. Then we can declare an operator= for BigNumberElement and do the range check inside the body of operator=.
class BigNum {
public:
class BigNumberElement {
public:
BigNumberElement &operator=(int rhs) {
// TODO : range check
val_ = rhs;
return *this;
}
private:
int val_ = 0;
};
BigNumberElement &operator[](size_t index) {
return element_[index];
}
BigNumberElement element_[10];
};
OLD answer
You can define a wapper, say NumWapper, which wraps a reference of BigNum's element. The operator= of BigNum returns the wrapper by value.
a[i]=11;
is then something like NumWrapper x(...); x = 11. Now you can do those checks in the operator= of NumWrapper.
class BigNum {
public:
NumWrapper operator[](size_t index) {
return NumWrapper(array_[index]);
}
int operator[](size_t index) const {
return array_[index];
}
};
In the NumWrapper, overload some operators, such as:
class NumWrapper {
public:
NumWrapper(int &x) : ref_(x) {}
NumWrapper(const NumWrapper &other) : ref_(other.ref_) {}
NumWrapper &operator=(const NumWrapper &other);
int operator=(int x);
operator int();
private:
int &ref_;
};
You can also declare the NumWrapper's copy and move constructor as private, and make BigNum his friend, for preventing user code from copying your wrapper. Such code auto x = a[i] will not compile if you do so, while user code can still copy the wrapped value by auto x = static_cast<T>(a[i]) (kind of verbose though).
auto &x = a[i]; // not compiling
const auto &x = a[i]; // dangerous anyway, can't prevent.
Seems we are good.
These is also another approach: store the elements as a user defined class, say BigNumberElement. We now define the class BigNum as :
class BigNum {
// some code
private:
BigNumberElement array_[10];
}
We need to declare a whole set operators for BigNumberElement, such as comparison(can also be done through conversion), assignment, constructor etc. for making it easy to use.
auto x = a[i] will now get a copy of BigNumberElement, which is fine for most cases. Only assigning to it will sometimes throw an exception and introduce some run-time overhead. But we can still write auto x = static_cast<T>(a[i]) (still verbose though...). And as far as I can see, unexpected compile-time error messages is better than unexpected run-time exceptions.
We can also make BigNumberElement non-copyable/moveable... but then it would be the same as the first approach. (If any member functions returns BigNumberElement &, the unexpected run-time exceptions comes back.)
the following defines a type foo::setter which is returned from operator[] and overloads its operator= to assign a value, but throws if the value is not in the allowed range.
class foo
{
int data[10];
public:
void set(int index, int value)
{
if(value<0 || value>9)
throw std::runtime_error("foo::set(): value "+std::to_string(value)+" is not valid");
if(index<0 || index>9)
throw std::runtime_error("foo::set(): index "+std::to_string(index)+" is not valid");
data[index] = value;
}
struct setter {
foo &obj;
size_t index;
setter&operator=(int value)
{
obj.set(index,value);
return*this;
}
setter(foo&o, int i)
: obj(o), index(i) {}
};
int operator[](int index) const // getter
{ return data[index]; }
setter operator[](int index) // setter
{ return {*this,index}; }
};
If what you are trying to do is overload [] where you can input info like a dict or map like dict[key] = val. The answer is actually pretty simple:
lets say you want to load a std::string as the key, and std::vector as the value.
and lets say you have an unordered_map as your underlying structure that you're trying to pass info to
std::unordered_map<std::string, std::vector<double>> myMap;
Inside your own class, you have this definition:
class MyClass{
private:
std::unordered_map<std::string, std::vector<double>> myMap;
public:
std::vector<double>& operator [] (std::string key) {
return myMap[key];
}
}
Now, when you want to load your object, you can simply do this:
int main() {
std::vector<double> x;
x.push_back(10.0);
x.push_back(20.0);
x.push_back(30.0);
x.push_back(40.0);
MyClass myClass;
myClass["hello world"] = x;
double x = myClass["hello world"][0]; //returns 10.0
}
The overloaded [] returns a reference to where that vector is stored. So, when you call it the first time, it returns the address of where your vector will be stored after assigning it with = x. The second call returns the same address, now returning the vector you had input.
I know that a return value is not enough to override a function (and I read different threads about it on stackoverflow), but is there a way to overload the subscript operator of a class, just to return the value (I can't changed to to return by reference-type of function)
It has to look like or at least work like:
What's the best approach to solve this problem (It has to be a operator)?
Update:
The Problem is, that's not allowed to just overload a member or operator just with the return type.
struct A {int a; int b; double c;};
struct B {int a; int b; array<double,2> c;};
class Whatever
{
public:
A operator [](unsigned int ) const; //it's just reading the element
B operator [](unsigned int ) const;
}
A operator [](unsigned int Input){
//...
}
B operator [](unsigned int Input){
//...
}
Assuming you know what kind of type you are going to access, you can return a proxy which converts to either type and, probably, does the access upon conversion. Since you want to access a const object that should be fairly straight forward. Things get a bit more messy when trying to do the same for an updating interface:
class Whatever;
class Proxy {
Whatever const* object;
int index;
public:
Proxy(Whatever const* object, int index)
: object(object)
, index(index) {
}
operator A() const { return this->object->asA(this->index); }
operator B() const { return this->object->asB(this->index); }
};
class Whatever {
// ...
public:
Proxy operator[](int index) { return Proxy(this, index); }
A asA(index) { ... }
B asB(index) { ... }
};
The main constraint is that you can't access members of A and B directly: you need to convert to an A or a B first. If the two types are actually known, you can created a Proxy which forwards the respective member function appropriately. Of course, if there are commonly named member functions or data members you'll need to explicitly convert first.
This question already has answers here:
How to overload array index operator for wrapper class of 2D array? [duplicate]
(2 answers)
Closed 9 years ago.
I've got a template of a class that shall behave like matrix.
So the usecase is something like:
Matrix matrix(10,10);
matrix[0][0]=4;
//set the values for the rest of the matrix
cout<<matrix[1][2]<<endl;
When I set the values directly in the constructor, it works well, but when I want to use matrix[x][y]=z; I get error: lvalue required as left operand of assignment. I assume, that I must overload = operator. Nevertheless I tried whole evening and I didn't find out, how to implement it. Would anybody be please so kind and show me how to overload = operator for my code, to make it assign values to that matrix?
code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <sstream>
using namespace std;
class Matrix {
public:
Matrix(int x,int y) {
_arrayofarrays = new int*[x];
for (int i = 0; i < x; ++i)
_arrayofarrays[i] = new int[y];
// works here
_arrayofarrays[3][4] = 5;
}
class Proxy {
public:
Proxy(int* _array) : _array(_array) {
}
int operator[](int index) {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
private:
int** _arrayofarrays;
};
int main() {
Matrix matrix(5,5);
// doesn't work :-S
// matrix[2][1]=0;
cout << matrix[3][4] << endl;
}
If you intend to modify the element of the matrix referenced by the proxy, then the overload of operator[] in the Proxy class must return a reference:
int& operator[](int index)
At the moment, you return int, which makes a copy of the element’s value—not what you want. There ought to be a const overload as well, so that operator[] works on const matrices. This one can return by value:
int operator[](int index) const
And actually, size_t would be more appropriate for the index than int, since it’s an unsigned type. You aren’t giving any particular meaning to negative indices, so it makes sense to disallow them.
You don’t need to overload operator= of Proxy unless you want to assign a whole row at once. In fact, you don’t need the Proxy class at all, because you can just return a pointer to the row array directly. However, if you want to change your design—e.g., using a sparse or packed representation—then the Proxy would let you keep the m[i][j] interface.
The issue is that you're returning an int value in proxy::operator[]. Your first [] operator returns the proxy object, the second returns an int. If your proxy [] operator were to return an int reference, then you would be able to assign to it:
int& operator[](int index) {
return _array[index];
}
I am writing a template Polynom<T> class where T is the numeric type of its coefficients.
The coefficients of the polynom are stored in an std::vector<T> coefficients, where coefficients[i] corresponds to x^i in a real polynom. (so the powers of x are in increasing order).
It is guaranteed that coefficients vector always contains at least one element. - for a zero polynom it is T().
I want to overload the operator[] to do the following:
The index passed to the operator[] corresponds to the power of X whose coefficient we want to modify / read.
If the user wants to just read the coefficient, it should throw for negative indices, return coefficients.at(i) for indices within the stored range - and reasonably return 0 for all other indices, not throw.
If the user wants to modify the coefficient, it should throw for negative indices, but let user modify all other indices freely, even if the index specified is bigger than or equal to coefficients.size(). So we want to somehow resize the vector.
The main problem I have collided with is as follows:
1.
How do I distinguish between the read case and the write case? One person left me without an explanation but said that writing two versions:
const T& operator[] (int index) const;
T& operator[] (int index);
was insufficient. However, I thought that the compiler would prefer the const version in the read case, won't it?
2.
I want to make sure that no trailing zeros are ever stored in the coefficients vector. So I somehow have to know in advance, "before" I return a mutable T& of my coefficient, what value user wants to assign. And I know that operator[] doesn't receive a second argument.
Obviously, if this value is not zero (not T()), then I have to resize my vector and set the appropriate coefficient to the value passed.
But I cannot do it in advance (before returning a T& from operator[]), because if the value to be assigned is T(), then, provided I resize my coefficients vector in advance, it will eventually have lots of trailing "zeroes".
Of course I can check for trailing zeroes in every other function of the class and remove them in that case. Seems a very weird decision to me, and I want every function to start working in assumption that there are no zeroes at the end of the vector if its size > 1.
Could you please advise me as concrete solution as possible to this problem?
I heard something about writing an inner class implicitly convertible to T& with overloaded operator=, but I lack the details.
Thank you very much in advance!
One option you could try (I haven't tested this):
template<typename T>
class MyRef{
private:
int index;
Polynom<T>*p;
public:
MyRef(int index, Polynom<T>*p) : index(index), p(p) { }
MyRef<T>& operator=(T const&t); //and define these appropriately
T operator T() const;
};
and define:
MyRef<T> operator[](int index){
return MyRef<T>(index, this);
}
This way when you assign a value to the "reference" it should have access to all the needed data in the polynomial, and take the appropriate actions.
I am not familiar enough with your implementation, so I'll instead give an example of a very simple dynamic array that works as follows:
you can read from any int index without concern; elements not previously written to should read off as 0;
when you write to an element past the end of the currently allocated array, it is reallocated, and the newly allocated elements are initialized to 0.
#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class my_array{
private:
T* _data;
int _size;
class my_ref{
private:
int index;
T*& obj;
int&size;
public:
my_ref(T*& obj, int&size, int index)
: index(index), obj(obj), size(size){}
my_ref& operator=(T const& t){
if (index>=size){
obj = (T*)realloc(obj, sizeof(T)*(index+1) );
while (size<=index)
obj[size++]=0;
}
obj[index] = t;
return *this;
}
//edit:this one should allow writing, say, v[1]=v[2]=v[3]=4;
my_ref& operator=(const my_ref&r){
operator=( (T) r);
return *this;
}
operator T() const{
return (index>=size)?0:obj[index];
}
};
public:
my_array() : _data(NULL), _size(0) {}
my_ref operator[](int index){
return my_ref(_data,_size,index);
}
int size() const{ return _size; }
};
int main(){
my_array<int> v;
v[0] = 42;
v[1] = 51;
v[5] = 5; v[5]=6;
v[30] = 18;
v[2] = v[1]+v[5];
v[4] = v[8]+v[1048576]+v[5]+1000;
cout << "allocated elements: " << v.size() << endl;
for (int i=0;i<31;i++)
cout << v[i] << " " << endl;
return 0;
}
It's a very simple example and not very efficient in its current form but it should prove the point.
Eventually you might want to overload operator& to allow things like *(&v[0] + 5) = 42; to work properly. For this example, you could have that operator& gives a my_pointer which defines operator+ to do arithmetic on its index field and return a new my_pointer. Finally, you can overload operator*() to go back to a my_ref.
The solution to this is a proxy class (untested code follows):
template<typename T> class Polynom
{
public:
class IndexProxy;
friend class IndexProxy;
IndexProxy operator[](int);
T operator[](int) const;
// ...
private:
std::vector<T> coefficients;
};
template<typename T> class Polynom<T>::IndexProxy
{
public:
friend class Polynom<T>;
// contrary to convention this assignment does not return an lvalue,
// in order to be able to avoid extending the vector on assignment of 0.0
T operator=(T const& t)
{
if (theIndex >= thePolynom.coefficients.size())
thePolynom.coefficients.resize(theIndex+1);
thePolynom.coefficients[theIndex] = t;
// the assignment might have made the polynom shorter
// by assigning 0 to the top-most coefficient
while (thePolynom.coefficients.back() == T())
thePolynom.coefficients.pop_back();
return t;
}
operator T() const
{
if (theIndex >= thePolynom.coefficients.size())
return 0;
return thePolynom.coefficients[theIndex];
}
private:
IndexProxy(Polynom<T>& p, int i): thePolynom(p), theIndex(i) {}
Polynom<T>& thePolynom;
int theIndex;
}
template<typename T>
Polynom<T>::IndexProxy operator[](int i)
{
if (i < 0) throw whatever;
return IndexProxy(*this, i);
}
template<typename T>
T operator[](int i)
{
if (i<0) throw whatever;
if (i >= coefficients.size()) return T();
return coefficients[i];
}
Obviously the code above is not optimized (especially the assignment operator has clearly room for optimization).
You cannot distinguish between read and write with operator overloads. The best you can do is distinguish between usage in a const setting and a non-const setting, which is what your code snippet does. So:
Polynomial &poly = ...;
poly[i] = 10; // Calls non-const version
int x = poly[i]; // Calls non-const version
const Polynomial &poly = ...;
poly[i] = 10; // Compiler error!
int x = poly[i] // Calls const version
It sounds like the answer to both your questions, therefore, is to have separate set and get functions.
I see two solutions to your problem:
Instead of storing the coefficients in a std::vector<T> store them in a std::map<unsigned int, T>. This way you will ever only store non-zero coefficients. You could create your own std::map-based container that would consume zeros stored into it. This way you also save some storage for polynomials of the form x^n with large n.
Add an inner class that will store an index (power) and coefficient value. You would return a reference to an instance of this inner class from operator[]. The inner class would overwrite operator=. In the overridden operator= you would take the index (power) and coefficient stored in inner class instance and flush them to the std::vector where you store your coefficients.
This is not possible. The only way I can think of is to provide a special member-function for adding new coefficients.
The compiler decides between the const and non-const version by looking at the type of Polynom, and not by checking what kind of operation is performed on the return-value.
I am trying to understand operators you need to overload when working with custom classes in STL(SCL).
Can any one please tell me what is it I am doing wrong ?
class myClass
{
public:
int data;
myClass()
{
data =0;
cout<<"Default const "<<endl;
}
myClass(int x)
{
data = x;
cout<<"Int constructor"<<endl;
}
myClass(const myClass &m)
{
cout<<"Copy constructor"<<endl;
}
bool operator == (const myClass &temp)
{
cout<<"Operator called &";
return data == temp.data;
}
bool operator == (const myClass *temp)
{
cout<<"Operator called *";
return data == temp->data;
}
};
int main ()
{
/*
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), meObj);
*/
vector<myClass*> myVec;
myClass temp;
myVec.push_back(&temp);
myClass temp2(19);
myVec.push_back(&temp2);
myClass temp3(19);
vector<myClass*>::iterator it = find(myVec.begin(),myVec.end(),&temp2); //works
if(it!=myVec.end())
{
cout<<"Value is "<<(*it)->data;
}
vector<myClass*>::iterator dit = find(myVec.begin(),myVec.end(),&temp3); //fails
if(dit!=myVec.end())
{
cout<<"Value is "<<(*dit)->data;
}
cout << endl;
return 0;
}
Please correct me if I am wrong, but the first find works as it does a address comparison. What do I need to overload for the above to work ?
Do both the signature make sense ?
bool operator == (const myClass &temp); // seen in many places
bool operator == (const myClass *temp); // what if two pointer types of same object are being compared?
Cheers!
Operator overloads must have at least one user-defined type. So you cannot overload operator== for two pointers, for instance.
Your myClass::operator==(const myClass *temp) is valid in the sense that it compiles, but makes very little semantic sense, and is not recommended (there are very few situations where you'd want to do T x; T *y; ... (x == y)).
For your situation, where you have a vector of pointers, you may want to consider std::find_if, which takes a predicate. Something like:
class CompareByPointer
{
public:
explicit CompareByPointer(const myClass &p) : p(p) {}
bool operator() (const myClass &rhs) const { return p->data == rhs->data; }
private:
const myClass &p;
};
...
find_if(myVec.begin(), myVec.end(), CompareByPointer(&temp2));
[As a side note, you should generally define member functions const wherever possible. So your operator overloads should be const.]
In the sample code, you haven't pushed &temp3 into myVec. So it makes sense for the second std::find to fail.
What do you mean by "work" in this case? Generally, when you're storing pointers, it's because the objects do have identity, and comparing the address is the correct thing to do. Otherwise, you should probably be storing values (although there are exceptions). Anyway, you can always use find_if, and any comparison criteria you want. For anything but the simplest types, I find myself using find_if more often than find anyway; usually, you're not looking for equality, but rather for some specific type of match. Here, for example, you'd more likely want something like:
std::vector<MyClass>::iterator it = std::find_if( myVect.begin(), myVect.end(),
boost::bind(&MyClass::id, _1, 19) );
(Supposing that the data here is some sort of identifier, and that you've provided a member function, myClass::id() to read it.)