I am trying to interface a C library to my C++ project. The library has its own vector type, assume to be VECTOR, and it provides element access:
int vector_set_value(VECTOR* vec, int index, double new_value);
int vector_get_value(VECTOR* vec, int index, double* retrieved_value);
Now it would be good to wrap the get and set operations by operator[] overloading
double& operator[](int index);
const double& operator[](int index) const;
But how do I tell operator[] have different behavior, between vec[index]=3 and double value=vec[3]? For the prior vector_set_value should be called while for the latter vector_get_value should be called.
I would not attempt to wrap one interface into the other.
That being said, if you really want to do this one possible solution is to create a proxy object, and have your operator[] return that proxy object. The proxy object would have conversions into the underlying type const double& for reading, and overloaded operator= for writing. Each one of them would call the appropriate library function.
This will allow for syntax that looks like that of C++ std::vector: MyVector v(...); v[1] = 10.1; double d = v[1]; but it will be problematic. The proxy object cannot replace the real type in all contexts, only in some of them. And even there, the semantics are different, so while it may look like a regular vector, one day you will try to use the proxy in a way it does not support and you will be puzzled at the leaking abstraction
Related
class vector{
public:
vector(int s);
double& operator[](int i);
int size();
private:
double∗ elem;
int sz;
};
Line 4 : double& operator[](int i);
what this line means in C++ programming principles, I get confused where & is used and [](int i) also quite confusing.
It defines the operator [] which returns a reference to the double value of the n-th element within the vector.
In this way you can read and write a specific element.
Suppose you have the following:
vector my_vector(1000);
With the operation double value = my_vector[3] you read the value of the 4th element.
With the operation my_vector[6] = 6.7 you set the value of the 7th element.
It allows you to user the [] parameter on the vector object.
it shows you that it receives an int as a parameter ([i]), and returns a double, so a line like the following will be valid:
double element = vector1[2];
or
vector1[2] = 4; // since the returned value is a reference
where vector1 is an instance of the vector class.
double& operator[](int i);
what this line means in C++
This line declares an operator[] (also known as the "Array subscript operator") implementation, which is commonly used for indexing container types (e.g. std::vector, std::map and others). Imagine the common sequence[0] to access the reference to the first element of a sequence.
where & is used
In C++, the & character appended to a type means "a type that represents a reference to type Foo". So for example int& is a reference to int, and double& is a reference to a double.
Now, why would you return references from an operator[]? The answer is: because you probably want to write code like this...
sequence[0] = 42;
...and for this you need operator[] implementation to return an lvalue. It just so happens that references are lvalues! Why do you need an lvalue? A simplistic answer is "because left-hand side of an assignment must be an lvalue". I found this article helpful when learning about lvalues and rvalues.
and [](int i) also quite confusing.
You parsed this somewhat incorrectly. Look at the declaration this way:
double&
operator[]
(int i)
First part is the return type, second is the name of the function you're implementing, and the third part specifies the parameters your function takes.
Implementations of operator[] should take an integer value (int, unsigned, size_t etc.) as a parameter (disclaimer: not sure, couldn't find a "thou shalt" reference for this). This is why your parameter list is (int).
Further reading: go to http://en.cppreference.com/w/cpp/language/operators and look for "Array subscript operator".
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 think I don't really understand what's behind references, and I'd be glad to learn more about those.
I'm writing a math "vector" Class to do basic linear algeabra for numerical simulation. I was using Eigen before i was convinced not to use external libraries anymore. My problem is pretty straightforward :
I declare vector and sets its 3 components of type Scalar (these are doubles). I can do math with my vectors as I overload operators, but this is beyond the scope of my question.
I want to access the i-th component of my object through the function call operator () as I was used with Eigen : myVector(0) = 0.0 ; or Scalar d = myVector(0)+1.0 ;
According to my understanding of references, this solution should be working :
class mtnVector {
public:
typedef double Scalar;
Scalar data [3];
(setters, math, etc...)
inline Scalar & operator() (const int i) const {
return data[i] ;
}
};
But g++ says that it doesn't like the way I implement it and comfirms I s*** at references :
Vector.h:185: error: invalid initialization of reference of type ?double&? from expression of type ?const double?
What's very strange from my point of view is that if the array containing the data is dynamically set (Scalar * data) (with new operator) at class construction, the code compiles fine. But I don't see the point of having dynamically set data holder.
I don't get neither the need of const to overload the function call operator but I accept it.
Your operator() is declared const. This means that calling the function should never end up modifying the object. That function returns a member of this object by non-const reference, which would allow whoever called operator() to modify the internals of the object. Obviously this would be silly, so the compiler just doesn't allow it. If you're going to return a reference to a member from a const member function, you need to make that reference const:
inline const Scalar& operator() (const int i) const {
return data[i] ;
}
You might want to provide both a const and non-const version of the function, one of which returns a const Scalar& and the other a Scalar& (this is how the standard library containers do it).
It seems strange that you'd want to use operator() for this. Your expression myVector(0) would look more natural as myVector[0], which you can achieve through overloading operator[] instead.
Also, you should ignore whoever convinced you that you shouldn't use external libraries. Eigen, in particular, is a very mature and thoroughly tested library. Unless you really have a good reason, you should be using it.
I am writing a matrix class and have overloaded the function call operator twice. The core of the matrix is a 2D double array. I am using the MinGW GCC compiler called from a windows console.
The first overload is meant to return a double from the array (for viewing an element).
the second overload is meant to return a reference to a location in the array (for changing the data in that location.
double operator()(int row, int col) const ; //allows view of element
double &operator()(int row, int col); //allows assignment of element
I am writing a testing routine and have discovered that the "viewing" overload never gets called. for some reason the compiler "defaults" to calling the overload that returns a reference when the following printf() statement is used.
fprintf(outp, "%6.2f\t", testMatD(i,j));
I understand that I'm insulting the gods by writing my own matrix class without using vectors and testing with C I/O functions. I will be punished thoroughly in the afterlife, no need to do it here.
Ultimately I'd like to know what is going on here and how to fix it. I'd prefer to use the cleaner looking operator overloads rather than member functions.
Any ideas?
The matrix class: irrelevant code omitted.
class Matrix
{
public:
double getElement(int row, int col)const; //returns the element at row,col
//operator overloads
double operator()(int row, int col) const ; //allows view of element
double &operator()(int row, int col); //allows assignment of element
private:
//data members
double **array; //pointer to data array
};
double Matrix::getElement(int row, int col)const{
//transform indices into true coordinates (from sorted coordinates
//only row needs to be transformed (user can only sort by row)
row = sortedArray[row];
result = array[usrZeroRow+row][usrZeroCol+col];
return result;
}
//operator overloads
double Matrix::operator()(int row, int col) const {
//this overload is used when viewing an element
return getElement(row,col);
}
double &Matrix::operator()(int row, int col){
//this overload is used when placing an element
return array[row+usrZeroRow][col+usrZeroCol];
}
The testing program: irrelevant code omitted.
int main(void){
FILE *outp;
outp = fopen("test_output.txt", "w+");
Matrix testMatD(5,7); //construct 5x7 matrix
//some initializations omitted
fprintf(outp, "%6.2f\t", testMatD(i,j)); //calls the wrong overload
}
The const member function (the "viewing" function) will only be called if the object is const:
const Matrix testMatD(5,7);
testMatD(1, 2); // will call the const member function
The overload which is called is determined solely by the parameters (including the this parameter) and not on the return type, or what you do with the return type.
This means that if you have a non-const method which has a signature that is otherwise identical to a const method (apart from possibly the return type) then the const method will only be used when called on a const object or through a const reference or pointer. When you have a non-const object, then non-const method will always be a better match.
Typically, the only way to make the distinction on whether you actually write to the returned object is to return some sort of proxy object which has an appropriate implicit conversion for reading and an overloaded assignment operator for writing. Needless to say, this usually adds considerable complexity.
Hey thanks everybody for your help, I had read similar responses to similar questions. I guess i just had to hear it one more time worded slightly differently.
My original problem was i needed two versions of the operator overload to be implemented differently depending on how that operator was being called.
-When the user simply needed to read a value, the overload would treat the matrix as const and do bounds checking to make sure the user was not trying to read data that doesn't exist.
-When the user needed to write data, the overload would resize the matrix accordingly.
of course this makes no sense as the method being called has no knowledge of what is calling it or what the user is trying to do (unless some data is passed in).
my solution was to make the operator overload execute the same for both a read and a write. thus, if the user attempts to read a location that doesn't exist, the matrix will re-size itself and return a default value. Ultimately this may sacrifice some speed if the user makes a mistake and reads data that doesn't exist, but if the user is doing that, the speed of the program is the least of his worries. so this requires that the user be a bit more careful, and i might add a data member that is a flag that indicates whether the matrix has been resized to easily allow the user to check if things went as expected.
I'm not going to post the code (unless requested) because this was more a high-level/functional problem, and the code contains so many specifics that it might cloud the discussion.
As others have mentioned, you need a const object to get a call of a const overload.
What you are trying to do here is ensure that the reference is transformed into an rvalue for ....
fprintf(outp, "%6.2f\t", double( testMatD(i,j) ) ); // double() for temporary
However, that conversion is performed automatically (§5.2.2/7) so special consideration is unnecessary.
Also, you might as well declare the two overloads to match. Make the "viewer" return a reference too.
double const &operator()(int row, int col) const ; //allows view of element
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.