Accessing c++ maps using a different class than the index - c++

Suppose you have a class:
class SomeClass{
public:
int x;
SomeClass(){
x = rand();
}
bool operator<(const SomeClass& rhs) const{
return x < rhs.x;
}
};
And then you have this:
map<SomeClass, string> yeah;
Obviously this will work:
yeah[SomeClass()] = "woot";
But is there a way to get something like this:
yeah[3] = "huh";
working? I mean, I tried setting operator<(int rhs) in addition to the other operator, but no dice. Is this possible at all?

Add a constructor:
SomeClass(int y){
x = y;
}

map's [] operator only takes the templated class as its parameter. What you want instead is some way of generating a specific instance of your class that has the values you want. In this example, add a constructor that lets you specify the value x should have.
class SomeClass{
public:
int x;
SomeClass(){
x = rand();
}
SomeClass(int a) : x(a){
}
bool operator<(const SomeClass& rhs) const{
return x < rhs.x;
}
};
And then use
yeah[SomeClass(3)] = "huh";
Or you can just use
yeah[3] = "huh";
which does the same thing, calling SomeClass's constructor implicitly.

You can't use yeah[3] as this will require the map to store keys of both SomeClass and int type;
Also, consider that each time you add a new element to the map, the "indexed" position of a certain element can change, as the elements are always mainteined ordered by the key element.
If you need to look at a certain point in time for the element no j, you can use probably use an iterator on the map.

Related

C++ Can I overload the bracket [] operator to do different things if it on the LHS vs RHS of an assignment?

I am looking to accomplish the following:
int x, y, z;
foo[x] = y; acts like do_this(x,y);
z = foo[x]; acts like z = do_that(x)
I can accomplish the first with a Foo class and a Helper class, where the operator[] returns by value a Helper class constructed with x, and the operator= for the Helper class is defined to run do_this(this->x, y). Like below:
class Foo {
public:
Helper operator[](int x) {
return Helper(x);
}
};
class Helper {
public:
Helper(x) {
this->x = x;
}
void operator=(int y) {
do_this(this->x, y);
}
private:
int x;
};
What I can't figure out is how to accomplish (2). Is there a way to overload the operator[] so that it knows if it was used on the lhs vs the rhs?
Yes - give your Helper class a conversion function to int:
class Helper {
public:
Helper(x){
this->x = x;
}
Helper& operator= (int y) {
do_this(this->x, y);
return *this;
}
operator int() const {
return do_that(this->x);
}
private:
int x;
};
This will also allow other uses like product *= foo[x]; or func_taking_int(foo[x]), etc.
One potential catch is that some uses of auto or function templates would still just keep the type Helper, which might not be what's wanted - so users of Foo should still understand that this proxy sugar is going on. It could also be helpful to have some alternative syntax to explicitly get the int value for cases like that, in either Foo or Helper.
I'm not sure I've understood what you actually want to do, but you are might be able to use the const version of the operator[] vs. the non-const version. For example:
struct Foo {
Z operator [] (int x) const { // this last const is important
return do_that(x);
}
Helper operator [] (int x) {
// as you yourself have written.
}
};
There are more tips and tricks to this, for forwarding arguments perfectly (a.k.a "perfect forwarding",) for being "const correct", and many other small things, but the gist of it is the above.

Square bracket [] operator overloading c++

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.

How to chain multiple operator[]

I am trying to create a class that use the operator [] like
MyClass[x][y]
and it should return a value based on what I call in the function that is defined within the class. What I have so far is:
MyClass.h
class MyClass{
public:
// return one value of the matrix
friend double operator[][] (const int x, const int y);
}
I don't even think my syntax for this is right, and how can I write this function in MyClass.cpp to define what value it should return?
Like is it:
MyClass::friend double operator[][] (const int x, const int y)
{
// insert code here
}
Tried it but it keeps saying errors. I believe it is a mess up there...
Many thanks,
Overloading operator() is definitely the cleanest approach.
However, remember that this is C++, and you can bend the syntax to your will :)
In particular, if you insist on wanting to use myclass[][], you can do so by declaring an "intermediate class", here's an example:
Run It Online
#include <iostream>
using std::cout;
using std::endl;
class MyClass {
public:
using IndexType = int;
using ReturnType = double;
// intermediate structure
struct YClass {
MyClass& myclass;
IndexType x;
YClass (MyClass& c, IndexType x_) : myclass(c), x(x_) {}
ReturnType operator[](IndexType y_) { return myclass.compute(x, y_); }
};
// return an intermediate structure on which you can use opearator[]
YClass operator[](IndexType x) { return {*this, x}; }
// actual computation, called by the last "intremediate" class
ReturnType compute(IndexType x, IndexType y) {
return x * y;
}
};
int main()
{
MyClass myclass;
cout << myclass[2][3] << endl; // same as: cout << myclass.compute(2, 3) << endl;
}
You need to return a proxy object for the row. This is a very simplified example just to get you going. I have not tried compiling it.
class Matrix {
int data[4][4];
class Row {
Matrix* matrix;
int row;
int operator[](int index){
return matrix->data[row][index]; // Probably you want to check the index is in range here.
}
}
Row operator[](int row){
Row which_row;
which_row.matrix = this;
which_row.row = row; // beware that if the user passes the row around it might point to invalid memory if Matrix is deleted.
return which_row;
}
}
You could also just return the row directly from operator[] and leave the second [] to be a direct array access. IMHO it is nice with the proxy object as it can do some checking on the index and possibly have other nice member functions.
There is no operator[][]. But you can declare operator()(int, int) instead.
class Foo {
public:
double operator()(int a, int b) {
//...
}
};
If you're trying to create 4x4 Matrix class, the way I did it and the way its done in the D3DX library is to have a member variable in the class:
class Matrix
{
public:
// publicly accessible member 4x4 array
float m[4][4];
// also accessible via () operator. E.G. float value = mtx(3,2);
float operator()(int column, int row);
}

Constructing result in operator vs operating on default-constructed object

I have a class which is essentially an array with labelled contents, and I'd like to define some operators for it. I'd like to do it in such a way that changing the number of elements in the class is easy, as I expect future users will change the variables tracked, but I'd also like to ensure that basic arithmetic operations on the class are as efficient as possible.
I can see two way of implementing the operators. Taking the example of a Vector2D class:
struct Vector2D {
//members
const static int nElem = 2;
double x;
double y;
//Constructors
Vector2D() {}
Vector2D(double X, double Y) : x(X), y(Y) {}
//Operators
double& operator[] (int index) {
switch(index) {
case 0:
return x;
case 1:
return y;
default:
return std::out_of_range ("Oops");
}
}
// Option 1: operator+ by constructing result
Vector2D operator+ (const Vector2D & rhs) const {
return Vector2D(x + rhs.x, y+rhs.y);
}
// Option 2: operator+ using loop and [] operator
Vector2D operator+ (const Vector2D & rhs) const {
Vector2D result;
for(int i = 0; i < nElem; i++)
result[i] = (*this)[i] + rhs[i];
return result;
}
};
Assuming I use -03 optimization, will there be any difference between the two implementations of operator+? My understanding is that since the default Vector2D constructor has no code body and the class contents are a default data type, there is no extra overhead in Option 2 for calling the default constructor on result before setting its members. I expect the two to be equivalent, but I'm not confident enough in my knowledge to be sure.
Your method won't work at all. If you want someone to be able to change nElem you can't use x, y as your names. Why? Because changing nElem to 3 won't magically add z. And since you can't do a for loop over x and y, your definition of nElem is meaningless.
Finally, this is a textbook case for the use of a number template. Create a vector which is templated over how many elements it has.
Do something like this:
template<unsigned int LEN>
class Vector{
double v[LEN];
public:
Vector operator+(const Vector &o){
Vector res;
for (unsigned int i=0;i<LEN;++i) // with -O3 and small LEN this will be unrolled
res.v[i]=v[i]+o.v[i];
}
// ... etc.
};
Then you use it like this:
Vector<2> my_2d_vec;
Vector<3> my_3d_vec;

compare function for upper_bound / lower_bound

I want to find the first item in a sorted vector that has a field less than some value x.
I need to supply a compare function that compares 'x' with the internal value in MyClass but I can't work out the function declaration.
Can't I simply overload '<' but how do I do this when the args are '&MyClass' and 'float' ?
float x;
std::vector< MyClass >::iterator last = std::upper_bound(myClass.begin(),myClass.end(),x);
What function did you pass to the sort algorithm? You should be able to use the same one for upper_bound and lower_bound.
The easiest way to make the comparison work is to create a dummy object with the key field set to your search value. Then the comparison will always be between like objects.
Edit: If for some reason you can't obtain a dummy object with the proper comparison value, then you can create a comparison functor. The functor can provide three overloads for operator() :
struct MyClassLessThan
{
bool operator() (const MyClass & left, const MyClass & right)
{
return left.key < right.key;
}
bool operator() (const MyClass & left, float right)
{
return left.key < right;
}
bool operator() (float left, const MyClass & right)
{
return left < right.key;
}
};
As you can see, that's the long way to go about it.
You can further improve Mark's solution by creating a static instance of MyClassLessThan in MyClass
class CMyClass
{
static struct _CompareFloatField
{
bool operator() (const MyClass & left, float right) //...
// ...
} CompareFloatField;
};
This way you can call lower_bound in the following way:
std::lower_bound(coll.begin(), coll.end(), target, CMyClass::CompareFloatField);
This makes it a bit more readable
Pass a lambda function to upper_bound
float x;
MyClass target;
target.x_ = x;
std::vector< MyClass >::iterator last =
std::upper_bound(myClass.begin(),myClass.end(),target,
[](const MyClass& a, const MyClass& b){return a.x_ < b.x_;});
I think what you need is std::bind2nd(std::less<MyClass>(), x). But, of course, the operator< must be defined for MyClass.
Edit: oh and I think you will need a constructor for MyClass that accepts only a float so that it can be implicitly converted. However, there might be a better way to do this.