Is it possible to create an "address of" (&) operator overload that would allow passing an arg? So kind of a mixture between overloading the operator [] and operator &.
So regular [] overload can be used like this
val = myobj[arg];
where:
SomeReturnType MyClass::operator[](SomeArgType i)
{
// Code to handle indexing
}
But if we want a pointer to that item, what I'm looking for would provide this use:
ptr = &myobj[arg];
Maybe this isn't possible directly, and I know there's other ways to achieve this, but if it is possible I do not know the syntax.
You do not need to overload adress of operator when operator[] returns a reference:
#include <iostream>
struct foo {
int x;
int& operator[](int){
return x;
}
};
int main() {
foo f;
std::cout << &f.x << "\n";
std::cout << &f[42] << "\n";
}
Possible output:
0x7ffc8cd2d46c
0x7ffc8cd2d46c
The example uses only a single int, but it will be the same when operator[] is returning reference to an element of some container.
Returning a copy from operator[] and then get the adress of the original element is not possible via operator& overload (unless you return some proxy that holds both, the copy of the element and the adress of the original, from operator[]).
Related
I'm currently trying to refactor some code which uses a primitive type into something which I can tuck setters and getters into them. I wanted to make the change to the underlying code transparent, and at first I though C++'s operator overloads would help me out there.
Let's suppose I want to make an "augmented int" type, for instance, that can be treated just like a regular int, but allows for further action wherever I assign to it, and just assignment - all other properties of an int, such as adding with +=, should be preserved.
At first I first though that if I encapsulated the int inside some struct, and filled out the operator= overloads, I'd be set, like in the following example:
#include<iostream>
typedef struct PowerInt{
int x;
PowerInt(){
cout << "PowerInt created\n";
x = 0;
}
~PowerInt(){
cout << "PowerInt destroyed\n";
}
void operator=(int other){
cout << "PowerInt received " << other << "\n";
this->x = other;
}
}PowerInt;
int main(){
PowerInt a;
a = 3;
return 0;
}
The code compiles and runs as expected, but as soon as I try making anything else a regular int could do, like cout << a, or a += 2, or even a simple int b = a; assignment the compiler complains about the operators << and += missing.
Fair enough; I then though that, at least for << and "assigment =", I could get by using some sort of "generic rvalue operator", or some kind of method which returns PowerInt.x wherever my a is used as an rvalue, automatically making expressions like int c = (a + 3); and if (a == 3) {} valid.
Problem is, I can't find a way to implement this idiom, and this mostly likely has to do with either my little understanding of how operator overloading works in C++, or some language feature I'm not yet aware of. Is it possible to accomplish what I'm trying here?
If you want your PowerInt to be convertible to a normal int you can create a user-defined conversion operator:
operator int() const
{
return x;
}
Any operator that's not defined for PowerInt will then use the operator defined for a normal int.
P.S The typedef struct isn't necessary in C++.
I've already overloaded operator [ ] to enable element access.
definition
double Matrix::operator[ ](const & int i){
return data[i]; // data[] is a member array: thrust:: device_vector
}
usage
Matrix m = ... // initialize
std::cout << m[3] << std::endl;
But now I want to access element by index so that assign new value to it.
usage
m[3] = 0.;
I understand the return value of the operator overload function must be an lvalue. I guess I should return a reference, but not sure how this is done. Thanks!
EDIT
Now I changed my definition to double &, but it still complains:
error: initial value of reference to non-const must be an lvalue
The array refers to a thrust::device_vector, which can be assigned value by index:
Thrust::device_vector<double> M(10);
M[3] = 0.;
Just replace
double ....
with
double& .....
change your definition to
double& Matrix::operator[ ](const & int i){
return data[i]; // data[] is a member array
}
Note, you should not use reference for an integer argument. It is usually used for complex classes for avoiding the copy. I would also suggest as a side note, to use m_memberVariable unless you use pimpl. This is what you should write:
double& Matrix::operator[ ] (const int i) {
return m_data[i]; // data[] is a member array
}
Note, you will need to add the '&' marker also in the class header where the method is declared.
This is all provided you have something like this in the class header:
class Matrix
{
private:
double m_data[100];
public:
double& operator[] (const int i);
};
Here you can read further details on the subscript operator overloading. This is another url for learning more about references.
As for a bit of inline explanation why it works like that:
You are trying to use the subscript operator on the left hand for assignment, hence the return value of such an operator overload has to be an l-value as you correctly state it. This is because if you return a value instead of reference, the left hand side in the usage would simply return that value which would evaluate to x = 0 where replace x with a value like 1. That is why you will get a compiler error in such cases.
Usually you chose to have a pair of operators. One for access:
double Matrix::operator[ ] const (const & int i){
return data[i];
}
and the other for assigment:
double &Matrix::operator[ ](const & int i){
return data[i];
}
If you call [ ] operator on a const object the first operator is really called. In other cases, both in access as well as assgnement, the second one is called.
You get error:
error: initial value of reference to non-const must be an lvalue
because data is (probably) a local variable. Make it a Matrix class private data member if it's not already.
noob here. The following is a fragment from a class definition I came accross in a book example:
double& operator[](int i);
double operator[](int i) const;
My question is: why is this not ambiguous? When compiling the files of the project, the compiler doesn't give any error.
Also, in the following (imagine AnyClass contains a valarray<double> object for example and I want to access it directly):
AnyClass test;
cout << test[2]
which version does the compiler use?
It's not ambiguous because the const is part of the signature and can be used for overload resolution. So if you use operator[] on a non-const object, it picks the overload without const because that's the most specific one. And if you use it on a const object, it picks the overload with const because that's the only one that applies.
If called on a const object, the const version will be used, else the other one.
That's how the compiler resolves the ambiguity.
AnyClass test;
const AnyClass const_test;
std::cout << test[2]; // calls operator[](int)
std::cout << const_test[2]; // calls operator[](int) const
To understand this, you mostly simply need to realize that a const on an argument is enough to disambiguate a call:
#include <iostream>
void foo(char* ptr)
{
std::cout << "mutable: " << ptr << std::endl;
}
void foo(const char* ptr)
{
std::cout << "const: " << ptr << std::endl;
}
int main()
{
const char* constHello = "hello";
char mutableHello[] = "hello";
foo(constHello);
foo(mutableHello);
}
This prints:
const: hello
mutable:hello
The compiler will choose the least restrictive overload it can. So if you use a char* when there's a char* overload, it's the one it will pick; but if there isn't any, the compiler will decide that casting it to a const char* is a viable conversion (the converse is, obviously, not true).
Now, the very simple thing is that all methods pass a this pointer as the first parameter of any function. This parameter is hidden for the sake of simplicity. The const at the end of the method qualifies the this argument. Since, as we've just seen, a const on a pointer is enough to disambiguate overloads, this will effectively work.
I have come across a function definition starting as:
int operator*(vector &y)
{
// body
}
After putting * just after operator and before opening brace of argument, what does this function mean?
This is an operator * overload. The syntax you should use is *(y) while y is of type vector.
It allows you a reference like implementation, something similar to pointer reference in C. Of course the actual meaning depends on the body. e.g. you can return a reference to an internal element in the vector.
This is a function overload for the * operator.
Its function overloading which overload the de-reference operator *.
It is either a dereferencing operator or a multiplication operator override. It is dereferencing if it is in a namespace and multiplication if it is inside a class. Since it has a body and no class scope I will also assume that it is a dereferencing.
Actually its not a deferencing operator as in *ptr! Its actually an operator such as a multiplication operator. Here is a simple example
#include <iostream>
using namespace std;
struct Int{
int val;
Int(const int val = 0) : val(val){}
int operator*(const Int& number)const{
return val * number.val;
}
};
int main(){
Int n(4), m(5);
cout << n * m << endl; //use the operator*() implicitly
cout << (n.operator*(m)) << endl; //use the operator* explicitly
}
To define a de-ferenceing operator, its prototype would be operator*(). Look here for more information. Here is a live code to test.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Overloading operator ->
Hi,
I've seen that operator->() is chained (re-applied) after it is evaluated, for example:
struct Bar
{
Bar() : m_str("Hello world!") {}
const string* operator->() const { return &m_str; }
string m_str;
};
struct Foo
{
const Bar& operator->() const { return m_bar; }
Bar m_bar;
};
int main()
{
Foo f;
cout << f->c_str() << endl;
return 0;
}
works pretty fine, which requires three operator->() to be evaluated - Foo::operator->(), Bar::operator->() and regular pointer resolution.
But it wont work with pointers in the middle - if Foo::operator->() returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>> for example.
Is it specific to non-overloaded operator->() so it is only applied once and does not cause chaining?
Is it possible to make code below works without using (*ptr2)-> ...?
int main()
{
string s = "Hello world";
auto_ptr<string> ptr1(&s);
auto_ptr<auto_ptr<string> > ptr2(&ptr1);
cout << ptr1->c_str() << endl; // fine
cout << ptr2->c_str() << endl; // breaks compilation
}
Thanks!
C++98 standard §13.5.6/1 "Class member access":
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).
What this means in practice is that when x is a pointer, you don’t get chaining; you then just get the built-in operator-> (i.e. x->m with x a pointer translates to (*x).m).
But when x is an object of class type T, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m can be that (x.operator->()) itself is an object of some class, say class U. Whence the second -> can be resolved as U::operator->, and so on, if the result of that again is a class type object…
Like, in your case, Foo::operator-> produces (a reference to) an object of class Bar, which does define an operator->.
But when operator-> returns a pointer, as e.g. std::auto_ptr<T>::operator-> does, then it's just the built-in operator-> that's used.
In passing, the chaining can be used to practically prevent someone from using delete inappropriately. std::auto_ptr does not do that. And I’ve never seen it done.
But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.
Cheers & hth.
The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr you actually are returned a real pointer and the default operator -> is invoked for regular pointers.
Please see the Overloading operator -> question for more details.
No, it is not possible for it to work. If you could overload operator -> for string * you could make it work. But operator -> already has a definition for all pointer types. So, just like you can't overload + for primitive numeric types, you can't overload operator -> for any pointer type.
And even if you could, how could the compiler know when the recursion should end?