I'm working on a class that overloads the index operator ([]). To allow for assignment of an element, it's necessary for the operator to return a reference to the element. For example:
class myclass: public vector<int>
{
...
public:
int & myclass::operator [] (int i)
{
return vector<int>::operator[](i);
}
...
In this situation, the client code can use the returned reference to assign a value to an element. However, I would like to have a way to intercept the actual assignment of the element so I can use the assigned value to do some internal housekeeping. Is there a relatively clean and simple way to do this, or should I just create some accessor functions instead of using operator overloading?
AFAIK the std::vector index operator already returns reference to the item (either const or non-const), so no need to inherit and override.
If you want to intercept the assignment of the value, the correct way of doing this is to define/override the assignment operator of the value itself (you cannot do it in the vector index operator). That will of course not work with pure int, so you'd need to wrap the int in a class which will provide the assignment operator and there you can do "anything you want".
EDIT:
Ok I see, so then it might be needed to do some overrides. For the reverse lookup, one of the possibilities could be to not store the value in the reverse structure, but a pointer to it (to the original location). The value assignment in the original structure would then be reflected with the pointer redirection. This would also need to pass a custom comparison operator to the reverse lookup map, to not compare the pointers, but the values.
In general, it might be worth to also check boost::multi_index, which allows to do exactly that - create a single structure with multiple lookup indices.
There is no way to intercept the assignment of an integer. However, you could instead return a reference to a custom type whose assignment operator you have overloaded. The custom type can be convertible to int, so that it can be used as one.
Of course, this means that you cannot inherit std::vector<int> which returns a reference to int. You should avoid inheriting std::vector publicly anyway. A user of your class may accidentally delete the object through a std::vector<int>* which would have undefined behaviour.
Related
By this question I am also trying to understand fundamentals of C++, as I am very new to C++. There are many good answers to problem of sorting a vector/list of custom classes, like this. In all of the examples the signature of comparator functions passed to sort are like this:
(const ClassType& obj1, const ClassType& obj2)
Is this signature mandatory for comparator functions? Or we can give some thing like this also:
(ClassType obj1, ClassType obj2)
Assuming I will modify the body of comparator accordingly.
If the first signature is mandatory, then why?
I want to understand reasons behind using const and reference'&'.
What I can think is const is because you don't want the comparator function to be able to modify the element. And reference is so that no multiple copies are created.
How should my signature be if I want to sort a vector which contains pointers to objects of custom class? Like (1) or (2) (see below) or both will work?
vertor to be sorted is of type vector
(1)
(const ClassType*& ptr1, const ClassType*& ptr2)
(2)
(ClassType* ptr1, ClassType* ptr2)
I recommend looking through This Documentation.
It explains that the signature of the compare function must be equivalent to:
bool cmp(const Type1& a, const Type2& b);
Being more precise it then goes on to explain that each parameter needs to be a type that is implicitly convertable from an object that is obtained by dereferencing an iterator to the sort function.
So if your iterator is std::vector<ClassType*>::iterator then your arguments need to be implicitly convertable to ClassType*.
If you are using something relatively small like an int or a pointer then I would accept them by value:
bool cmp(const ClassType* ptr1, const ClassType* ptr2) // this is more efficient
NOTE: I made them pointers to const because a sort function should not modify the values it is sorting.
(ClassType obj1, ClassType obj2)
In most situations this signature will also work, for comparators. The reason it is not used is because you have to realize that this is passing the objects by value, which requires the objects to be copied.
This will be a complete waste. The comparator function does not need to have its own copies of its parameters. All it needs are references to two objects it needs to compare, that's it. Additionally, a comparator function does not need to modify the objects it is comparing. It should not do that. Hence, explicitly using a const reference forces the compiler to issue a compilation error, if the comparator function is coded, in error, to modify the object.
And one situation where this will definitely not work is for classes that have deleted copy constructors. Instances of those classes cannot be copied, at all. You can still emplace them into the containers, but they cannot be copied. But they still can be compared.
const is so you know not to change the values while you're comparing them. Reference is because you don't want to make a copy of the value while you're trying to compare them -- they may not even be copyable.
It should look like your first example -- it's always a reference to the const type of the elements of the vector.
If you have vector, it's always:
T const & left, T const & right
So, if T is a pointer, then the signature for the comparison includes the comparison.
There's nothing really special about the STL. I use it for two main reasons, as a slightly more convenient array (std::vector) and because a balanced binary search tree is a hassle to implement. STL has a standard signature for comparators, so all the algorithms are written to operate on the '<' operation (so they test for equality with if(!( a < b || b < a)) ). They could just as easily have chosen the '>' operation or the C qsort() convention, and you can write your own templated sort routines to do that if you want. However it's easier to use C++ if everything uses the same conventions.
The comparators take const references because a comparator shouldn't modify what it is comparing, and because references are more efficient for objects than passing by value. If you just want to sort integers (rarely you need to sort just raw integers in a real program, though it's often done as an exercise) you can quite possibly write your own sort that passes by value and is a tiny bit faster than the STL sort as a consequence.
You can define the comparator with the following signature:
bool com(ClassType* const & lhs, ClassType* const & rhs);
Note the difference from your first option. (What is needed is a const reference to a ClassType* instead of a reference to a const ClassType*)
The second option should also be good.
I am new to C++ and currently am learning about templates and iterators.
I saw some code implementing custom iterators and I'm curious to know what the difference between these two iterator parameters is:
iterator & operator=(iterator i) { ... i.someVar }
bool operator==(const iterator & i) { ... i.someVar }
They implement the = and == operators for the particular iterator. Assuming the iterator class has a member variable 'someVar', why is one operator implemented using "iterator i" and another with "iterator & i"? Is there any difference between the two "i.someVar" expressions?
I googled a little and found this question
Address of array - difference between having an ampersand and no ampersand
to which the answer was "the array is converted to a pointer and its value is the address of the first thing in the array." I'm not sure this is related, but it seems like the only valid explanation I could find.
Thank you!
operator= takes its argument by value (a.k.a. by copy). operator == takes its argument by const reference (a.k.a. by address, albeit with a guarantee that the object will not be modified).
An iterator may be/contain a pointer into an array but it is not itself an array.
The ampersand (&) has different contextual meanings. Used in an expression, it behaves as an operator. Used in a declaration such as iterator & i, it forms part of the type iterator & and indicates that i is a reference, as opposed to an object.
For more discussion (with pictures!), see Pass by Reference / Value in C++ and What's the difference between passing by reference vs. passing by value? (this one is language agnostic).
the assignment operator = takes the iterator i as value, which means a copy of the original iterator is made and passed to the function so any changes applied to the iterator i inside the operator method won't affect the original.
the comparison operator == takes a constant reference, which denotes that the original object can't/shouldn't be changed in the method. This makes sense since a comparison operator usually only compares objects without changing them. The reference allows to pass a reference to the original iterator which lives outside the method. This means that the actual object won't be copied which is usually faster.
First, you don't have an address of an array here.
There's no semantic difference, unless you try to make a local change to the local variable i: iterator i will allow a local change, while const iterator & i will not.
Many people are used to writing const type & var for function parameters because passing by reference can be faster than by value, especially if type is big and expensive to copy, but in your case, an iterator should be small and cheap to copy, so there's no gain from avoiding copying. (Actually, having a local copy can enhance locality of reference and help optimization, so I would just pass small values by value (by copying).)
I am wondering if there is a way to overload operator[] for a non-class type in C++.
Basically, there is a data type which is a pointer (CFDictionaryRef from CoreFoundation). But it's not a class (i know that overloading operator[] for a specific class is allowed). I know how to access each element inside the CFDictionaryRef (for example, by using CFDictionaryGetIndex(CFIndex index); ). I want to make it simplified so that I don't have to write that function call every time. I want to overload the operator[ ] for CFDictionaryRef. But since it's not a class, from what I see, it's not possible.
Anyone got any suggestions?
You're right, it's not possible to overload operators on non-user-defined types.
What you might do is wrap the pointer in a class and overload the operators on the class itself. Since you can only overload operators on class types, this is the only option.
class CFDictionaryRefWrapper {
public:
CFDictionaryRefWrapper(CFDictionaryRef r) : dref(r) { }
CFDictionaryRef dref;
Type operator[](unsigned int index) {
/* do whatever with dref */
}
};
This also has the advantage of being able to automatically manage the lifetime of the pointer (RAII) if you need to do that.
No, you cannot overload the [] operator for a pointer type, or any other built-in type. In fact, ptr[N] already is a shorthand for *(ptr + N).
You'd need to define your own class which wraps the pointer if you want to overload the [] operator.
Is it possible to overload operators in such a way that you can capture a specific combination of them? For example lets say I have a custom object myObject of type MyType where [] is already overloaded to pass such calls down to a map object. That said, in the case of the following code:
int value = myObject["someProp"];
I'm already overloading [] but in this case I'd like to know when [] is being called on the object in an assignment, with a reference to the type of object that the property lookup is to be assigned to. This way I can cast the value coming out of the dynamic property lookup and so on and so forth. Any input is appreciated!
For more insight into exactly what I'm trying to accomplish, see this related question of mine.
No, you can't overload on the return type, or on the context in which the call appears (e.g. in an assignment etc).
You could, however, return a proxy object that would have a bunch of overloaded conversion operators. Without seeing what you intend to do, it's hard to say how far you might be able to get with this approach, or whether it's even a sane thing to do.
If you want type deduction for things like this, your best bet is to overload operator() instead, and pass in the thing you're going to be assigning to as a dummy parameter, i.e.:
MyType myObject;
int value = myObject("someProp", value);
I've made something like this work pretty well in the past. In particular, see e.g.:
https://github.com/sgolodetz/hesperus2/blob/master/source/engine/core/hesp/objects/base/ObjectManager.tpp
In principle, it's rather straightforward to do: all that is needed is
for your operator to return a proxy which then overloads the operators
you want to catch. In practice, it can cause more than a few problems;
readers will expect (a op1 b) op2 c to have
the same semantics as T tmp(a ip1 b); tmp op2
c. There are some common exceptions, however:
The operator[] in a multi-dimensional array will often return a
proxy which defines an operator[] itself, in order to support [][]
correctly.
More generally, a container which for whatever reasons needs to know
when a value is modified will have an operator[] which returns a
proxy; within the proxy, assignment is defined as setting the value in
the owning container, and there will be a convertion operator to the
value type, for use in rvalue contexts. Of course, this means that
things like m[i][j].funct() don't work; typically, however, this sort
of thing is used for matrices of numeric types, where member functions
aren't that relevant.
In contexts where it is desirable to support overload resolution based
on the target type (your example), the function can return a proxy with
overloaded conversion operators. You want to be extremely careful with
this—overloaded conversion operators are often a recipe for
overload resolution ambiguities&rdash;but there are enough exceptions
that this situation bears mentionning. (Important, here, is that the
results of the operator will amost always be used to intialize or to
assign to a specific object, the type of which determines which
conversion operator will be called.)
BTW: I might mention that in the example you give, there is no
assignment; it is a classical initialization. In this case, defining
the operator[] to return a proxy which defines operator int() const
would do the trick very well. Before going this route, however, you
should very definitely consider all of the use cases of your class, and
ensure that there are none in which the actual target type is ambiguous.
The other answers are basically correct that you can't do it. aix hints at a solution of a custom return type with overloaded conversion operators, but rightly indicates it isn't a sane thing to do. I've ventured down this path quite often and ultimately implicit conversions, and sequences of conversions, and ambiguities will bite you in you in the behind.
I've had a need of this quite often though. Ultimately I end up going for a series of overloaded functions, or templates, depending on your needs, perhaps like this:
void lookup( int& v, char const * name );
void lookup( double& c, char const * name );
In the template case I created global converters and did the below member function:
template<T>
void lookup( T&v, char const* name ) { v = convert<T>( get(name) ); }
If you want to keep the return value as the lookup you'll have to explicitly call a templated function.
template<T> T get( char const * name ) { ... }
//use
int a = obj.get<int>( "name" );
double b = obj.get<double>( "floaty" );
No, you can't do that.
Moreso, madness that way lies!
I'm trying to create a "sparse" vector class in C++, like so:
template<typename V, V Default>
class SparseVector {
...
}
Internally, it will be represented by an std::map<int, V> (where V is the type of value stored). If an element is not present in the map, we will pretend that it is equal to the value Default from the template argument.
However, I'm having trouble overloading the subscript operator, []. I must overload the [] operator, because I'm passing objects from this class into a Boost function that expects [] to work correctly.
The const version is simple enough: check whether the index is in the map, return its value if so, or Default otherwise.
However, the non-const version requires me to return a reference, and that's where I run into trouble. If the value is only being read, I do not need (nor want) to add anything to the map; but if it's being written, I possibly need to put a new entry into the map. The problem is that the overloaded [] does not know whether a value is being read or written. It merely returns a reference.
Is there any way to solve this problem? Or perhaps to work around it?
There may be some very simple trick, but otherwise I think operator[] only has to return something which can be assigned from V (and converted to V), not necessarily a V&. So I think you need to return some object with an overloaded operator=(const V&), which creates the entry in your sparse container.
You will have to check what the Boost function does with its template parameter, though - a user-defined conversion to V affects what conversion chains are possible, for example by preventing there being any more user-defined conversions in the same chain.
Don't let the non-const operator& implementation return a reference, but a proxy object. You can then implement the assignment operator of the proxy object to distinguish read accesses to operator[] from write accesses.
Here's some code sketch to illustrate the idea. This approach is not pretty, but well - this is C++. C++ programmers don't waste time competing in beauty contests (they wouldn't stand a chance either). ;-)
template <typename V, V Default>
ProxyObject SparseVector::operator[]( int i ) {
// At this point, we don't know whether operator[] was called, so we return
// a proxy object and defer the decision until later
return ProxyObject<V, Default>( this, i );
}
template <typename V, V Default>
class ProxyObject {
ProxyObject( SparseVector<V, Default> *v, int idx );
ProxyObject<V, Default> &operator=( const V &v ) {
// If we get here, we know that operator[] was called to perform a write access,
// so we can insert an item in the vector if needed
}
operator V() {
// If we get here, we know that operator[] was called to perform a read access,
// so we can simply return the existing object
}
};
I wonder whether this design is sound.
If you want to return a reference, that means that clients of the class can store the result of calling operator[] in a reference, and read from/write to it at any later time. If you do not return a reference, and/or do not insert an element every time a specific index is addressed, how could they do this? (Also, I've got the feeling that the standard requires a proper STL container providing operator[] to have that operator return a reference, but I'm not sure of that.)
You might be able to circumvent that by giving your proxy also an operator V&() (which would create the entry and assign the default value), but I'm not sure this wouldn't just open another loop hole in some case I hadn't thought of yet.
std::map solves this problem by specifying that the non-const version of that operator always inserts an element (and not providing a const version at all).
Of course, you can always say this is not an off-the-shelf STL container, and operator[] does not return plain references users can store. And maybe that's OK. I just wonder.