I have a class Foo that encapsulates access to a vector and provides access to it via the subscript operator:
typedef int* IntPtr;
class Foo {
std::vector<IntPtr> bars;
IntPtr& operator[](size_t idx) {
return bars[idx];
}
};
In class Bar i want to use Foo. While solution 1 works, it is rather inconvenient. I would prefer something like solution 2. Obviously, a method call (even if it returns an lvalue) can't be assigned something, albeit the method call doesn't do anything else than solution 1.
class Bar {
Foo *foo; //some initialization
IntPtr helper(size_t idx) {
return (*foo)[idx];
}
void barfoo() {
size_t baz = 1;
IntPtr qux;
//solution 1
qux = (*foo)[baz]; //works
(*foo)[baz] = &1; //works
//solution 2
qux = helper(baz); //works
helper(baz) = &1; //does not work: "expression is not assignable"
}
};
Question: How can I simplify the usage of an overloaded subscript operator?
EDIT: Changed used type to from int to int*. Sorry, I screwed up when creating the example.
I guess the problem is because of the twisted int*&.
The best way is to write a regular method, e.g Foo::at(size_t idx), providing the same functionality as your operator.
Notice that the STL does the same (just take a look at std::vector).
You can then simply call foo->at(baz);. To avoid rendundancy you could change the implementation of operator[]:
int& operator[](size_t idx) {
return at(idx);
}
In your snippet, you cant assign a value to the return because you have forgotten to return a reference.
Not that nice but an alternative would be foo->operator[](baz); though I strongly discourage you to write such an ugly code.
Darn. I just forgot to let helper return the value via a reference:
IntPtr& helper(size_t idx)
or
int*& helper(size_t idx)
Related
EDIT: This question is not for overriding the operator [] I know how to do that
I have implemented My own collection class, and for assigning data I would like to provide the same operators/functions as std::vector.
However, I have not been able to find a way to define the operators [index]=elm and at(index) = elm.
I am not even completely sure what to terms to search for as these two are not exactly operators
Define your operator[] overload and your at function to return a reference to the specified item. You can then assign the new value through that reference.
There is no []= operator. If your operator[] function returns a reference that can be assigned to, that's all you need.
Simple example to demonstrate the idea.
struct Foo
{
int i;
int& operator[](int) { return i; };
int operator[](int) const { return i; };
}
Now you can use
Foo f;
f[10] = 20; // The index is not used by Foo::operator[]
// This is just to demonstrate the syntax.
You need to do the same with the at() function.
So I think I might be overthinking this but I wanted to know if someone could clarify why the following statement works in the given code
f->hello();
This is the code
struct bar
{
void hello()
{
std::cout << "Hello World";
}
};
struct foo
{
bar* f;
foo() {
f = new bar();
}
~foo() {
delete f;
}
bar* operator->() {
return f;
}
};
int main()
{
foo f;
f->hello(); //Works
}
Since the following code from above returns a pointer
bar* operator->() {
return f;
}
should'nt
f->hello(); actually be f->->hello();
why does f->hello() work and f->->hello() fails ?
The reason i am thinking that f->->hello() should work is because
f->ptrReturned->hello();
If we overload the -> operator are we required to return a ptr type ? Form what I have tried it seems returning an object type is not allowed
Your understanding is correct basically, but ->-> is not valid syntax. You can use the overloaded operator-> like
f.operator->()->hello();
//^^^^^^^^^^^^ return the pointer
// ^^^^^^^^^ call hello() on the returned pointer
f->hello() is treated as the same of f.operator->()->hello(); that makes the usage of class with overloaded operator-> (e.g. smart pointers) consistent with built-in pointers. The usage would be more natural, and could be used with raw pointers in more general context like templates.
And,
If we overload the -> operator are we required to return a ptr type ?
There're some restrictions:
The overload of operator -> must either return a raw pointer, or return an object (by reference or by value) for which operator -> is in turn overloaded.
Apparently, that's just how an overloaded operator-> works. The part before the -> (not including the operator itself) gets replaced with the return value of the overloaded operator. For example, std::unique_ptr::operator-> returns a pointer, which then gets dereferenced by the ->.
I have this function call:
uint32_t func(uint32_t* a, uint32_t b)
I want to call it with an integer literal like this:
func(0, b);
where b is a uint32_t.
Is there any way I can do this without creating an intermediate variable?
I.e. I want to avoid doing this:
uint32_t a = 0;
func(a, b);
A helper class:
struct int_ptr {
int v;
operator int *() { return &v; }
};
int foo(int *a, int b);
void bar()
{
foo(int_ptr{0}, 0);
}
This results in a construction of a temporary int_ptr class, initializing its v member to 0. This gets passed as a parameter to a function that takes an int *, and int_ptr provides a suitable operator * method that passes the right pointer to the function.
This entire house of cards hinges on the fact that the int_ptr temporary exists until the end of the function call. You should pick a name for the helper class to underline that fact. If you always use it to pass a pointer to 0 to foo, then spell it out:
struct zero_value_to_foo {
int v=0;
operator int *() { return &v; }
};
int foo(int *a, int b);
void bar()
{
foo(zero_value_to_foo{}, 0);
}
So that using it in other contexts will look to be very much out of place, i.e.
int *p=zero_value_to_foo{};
This compiles, but leaves you with a dangling pointer; but hopefully the "zero_value_to_foo" label gives a honking clue that something is wrong here.
Another little thing you can do to help yourself from misusing this is to use a ref qualifier for the operator:
struct zero_value_to_foo {
int v=0;
operator int *() && { return &v; }
};
With this,
foo(zero_value_to_foo{}, 0);
still compiles, but not this:
zero_value_to_foo zero{};
foo(zero, 0);
The more that can be done to make it difficult to use this except in the context is meant for, the fewer opportunities there are for bugs to creep by.
I am assuming you want to pass a pointer to an integer 0, and not the 0 (NULL) pointer.
If you don't mind allocating dynamic memory you can do this:
func(new uint32_t(0), b);
However, then you'd have to make sure to deallocate the memory inside the function.
Alternatively, you can use an R-value references (c++11).
Then you can use the address of the reference as the pointer inside your function.
R-value reference syntax:
uint32_t func(uint32_t &&a, uint32_t b);
In a project of mine, I'm writing a wrapper for std::vector. I'm doing this because I am using homogeneous coordinates and for some operations it's just easier to temporarily 'forget' the fourth coordinate.
Now I stumbled upon a problem. I have loads of assignments like the following:
Vector v;
v(0) = 5;
v(1) = 6;
and so on. I also want to do the following:
double x;
x = v(0);
For that last thing, I can overload the () operator, but how would implement the first thing? (the zero and one being an index).
Just return reference.
class Vector
{
int data[4];
int & operator() (int index) { return data[index]; }
};
Return a non-const reference to the element to be modified.
Two things-
You should probably be overloading operator[] to do this rather than operator(), since it's the more natural operator here. operator() is used to create function objects, while operator[] is the operator meaning "pick out the element at this position."
You can support assignment to the result of operator[] / operator() by having the function return a reference to the value that should be written to. As a simple example, here's some code that represents a class wrapping a raw array:
(code here:)
class Array {
public:
int& operator[] (unsigned index);
int operator[] (unsigned index) const;
private:
int array[137];
};
int& Array::operator[] (unsigned index) {
return array[index];
}
int Array::operator[] (unsigned index) const {
return array[index];
}
The second of these functions is a const overload so you can have const Array read but not write values.
In the standard libraries, such things are implemented by having operator() (well, actually usually operator[]) return type double &. By returning a reference to a double, you can assign to or from it.
However, are you sure you want to wrap this around std::vector? This class is not a vector in the mathematical sense; it's much like a Java ArrayList, and so not at all efficient for small structures. Usually when I'm writing my own vector classes I'm planning on having lots of them around, so I implement a class from scratch on top of a static array.
Consider this code:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
No compiler complains about it, even Clang. Why q() = ... line is correct?
No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)
If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)
The reason that this works is that you are allowed to call member functions (even non-const member functions) on r-values of class type and the assignment of foo is an implementation defined member function: foo& foo::operator=(const foo&). The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.
This is why it is sometimes recommended to return objects of class type as const objects (e.g. const foo q();), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.
Because structs can be assigned to, and your q() returns a copy of struct foo so its assigning the returned struct to the value provided.
This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).
This makes more sense (though still not really a "best practice")
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
One interesting application of this:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
Here, g() += modifies the temporary, which may be faster that creating an additional temporary with + because the heap allocated for g()'s return value may already have enough spare capacity to accommodate </tag>.
See it run at ideone.com with GCC / C++11.
Now, which computing novice said something about optimisations and evil...? ;-].
On top of other good answers, I'd like to point out that std::tie works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern