Some hours ago I read this question in which the user initialized a const object as
const QList warnings = QList() << 0 << 3 << 7;
Indeed, this expression somehow hurt me because going against the concepts I have of const and of overloading operator<<.
I tried to define an operator<< possibly allowing for the mentioned expression and here is what I got:
typedef vector<int> Vect;
Vect operator<<(Vect v, const int i){ //ByVal v, This way it works, but at which cost?
v.push_back(i); //v is copied at every call!
return v;
};
//Here is where I build the object
const Vect const_vect = Vect() << 1 << 2;
//it works fine but I see massive overhead due to copies..#_#
//Just for testing
int main() {
for(auto e = const_vect.begin(); e!=const_vect.end() ; ++e){
cout << *e << " ";
}
return 0;
}
The previous code (which is also here) works fine.
The following, on the other hand, is the expression I would have expected from the definition of operator<<:
Vect& operator<<(Vect& v, const int i){ //ByRef v<-this I would have expected;
v.push_back(i); //however it can't work because receives and
return v; //returns reference to temporary object.
};
My question is: what am I missing? is the operator<< defined in QList differently implemented from mine, in particular, can it receive and return ByRef?
Secondly, is perhaps the aforementioned a standard procedure to initialize complex const objects?
Thirdly (maybe inconvenient), how would such an expression handled by the compiler? what is done at compile-time and what at run-time?
Related
The main problem is that when typing cout<<f1; alone it worked as well as f1++; alone but when attempting to enter cout<<f1++; together it shows that error knowing that when making the post increment it is returning a fraction object.
ostream& operator <<(ostream& output, fraction& fraction1)
{
output << "[" << fraction1.num << "/" << fraction1.denom << "]" << endl;
return output;
}
fraction fraction::operator ++(int)
{
fraction temp = *this;
++(this->num);
++(this->denom);
return temp;
}
int main()
{
fraction f1;
cout << f1;
f1++;
cout << f1++ << endl; // Results in compiler error
return 0;
}
The compiler error is: no operator "<<" matches these operands
Reasoning by analogy, consider this setup:
void doSomething(int& x) {
x = 137;
}
int main() {
doSomething(42); // Oops!
}
This code won’t compile because there’s an error in the indicated line. The function doSomething expects an int&, which you can think of as meaning “please give me an actual int variable or int object somewhere that I can change.” But 42 isn’t an int variable - it’s a pure value, hence the error.
Now, suppose you change main to this:
int main() {
int var = 42;
doSomething(var++); // Oops!
The expression var++ means “increment var, then hand back the value it used to have.” That means that we’re still passing the pure value 42 into the function, and since the function wants objects and not values, this won’t compile.
However, you can make this version of main work by changing doSomething to take in a const int&:
void doSomething(const int& x) {
// do something other than change x
}
This code works just fine due to how C++ defines const references. Unlike a regular reference, which means “I’d like to be able to change this object,” a const reference works fine when you pass in a pure value, since the const bit means “I promise not to actually change anything here.”
Now, look at your code. It’s basically the same idea as what’s shown above: you have a function named operator<< whose second parameter is a fraction&. That means that you can’t pass in the result of the ++ operator. And the fix is the same - just change the second parameter to use a const reference.
Hope this helps!
Let's look at the following C++ code:
#include <iostream>
int main()
{
int z = 2;
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3;
a.show();
}
The program prints: 2 and 3
It clearly shows that while inside class A x can't be modified, it merely means it's read only, because I can change it's value from outside.
Of course I can make it a copy stored inside class A, but I'm wondering if there is (or if there is a proposal?) of a way to say to class A that the member x will be truly constant instead of merely read only, with the meaning of a promise that the external code won't change it ?
To my eyes it looks like something related to the meaning of the C restrict keyword, but I've not heard of any such C++ feature yet. Do you ?
Constness is an attribute of the actual variable.
The term const int& x simply means "x is a reference to an int which it will not modify" and of course the compiler enforces this.
If you want the actual variable to which x refers to be const, simply declare it so:
#include <iostream>
int main()
{
const int z = 2; // declared const. Nothing may ever modify it
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3; // this is a logic error, caught by the compiler.
a.show();
}
compiling correctly produces the error:
./const.cpp:41:7: error: read-only variable is not assignable
z = 3;
~ ^
1 error generated.
You're looking for D's immutable keyword, which was introduced as a new concept in that language precisely because, unfortunately, the answer is no: it does not exist in C++.
Constness in C++ does not mean immutability, but that the variable in question is read-only. It can still be modified by other parts of the program. I understand your question as to whether it's possible to enforce true immutability in a called function without knowing what the caller is doing.
Of course you can create a template wrapper class which accomplishes the task:
template <typename T>
class Immutable
{
public:
template <typename ...Args>
Immutable( Args&&...args )
: x( std::forward<Args>(args)... )
{}
operator const T &() const
{
return x;
}
private:
const T x;
};
As long as you do not reinterpret_cast or const_cast you will have truly immutable objects when you wrap them with Immutable<T>.
However, if you have a constant reference to some object, there is no way to tell, if some other part of the program has a non-constant access to the object. In fact, the underlying object might be a global or static variable, that you have read-only access to, but functions you call might still modify it.
This cannot happen with Immutable<T> object. However, using Immutable<T> might impose an extra copy operation on you. You need to judge yourself if you can live with that and if the cost justifies the gain.
Having a function require an const Immutable<Something> & instead of const Something & as an argument affects the calling code. A copy operation might be triggered. Alternatively, you can ask for an Immutable<Something> & without the const. Then no accidental copies will be triggered, but the calling code must pass a reference to Immutable<Something> object. And rightly so, because if the caller received a const & as an argument then the caller does not know, whether the object might get modified by someone else in the program. The caller has to create the object itself or require an immutable object to be passed to it as a reference.
Your original question
Here's your original problem with Immutable<int> & instead of const int &.
#include <iostream>
int main()
{
Immutable<int> z = 2;
class A {
public:
const Immutable<int> & x;
A(Immutable<int> & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
//z = 3; // this would fail
a.show();
}
An other example
Here's how it works: If you write
void printAndIncrementAndPrint( int & i1, const int & i2 )
{
std::cout << i2 << std::endl;
++i1;
std::cout << i2 << std::endl;
}
int main()
{
int i = 0;
printAndIncrementAndPrint( i, i );
}
then it will print
0
1
into the console. If you replace the second argument of printAndIncrementAndPrint() with const Immutable<int> & i2 and keep the rest the same, then a copy will be triggered and it will print
0
0
to the console. You cannot pass and Immutable<int> to the function and a int & to the same underlying data without breaking the typesystem using const_cast or reinterpret_cast.
I think this is a design problem for the programmers, not the language. A const variable means for any user of that variable, they should not change the value of that variable. Our compiler is smart enough to help us make sure of that. So A is a user of z and if you want A know that A::x references to a const variable, then you should make z a const int. The const reference is just to keep the contract between the user and the provider.
I've received an excercise to implement a generic Matrix class.
One of the tasks is as follows: "Overload operator() which gets parameterse (unsigned int, unsigned int) twice, once as const and once as a non-const.".
Now, after much searching, I understood that this should be how their signatures:
T operator()(unsigned int rows, unsigned int colls) const; //cout << "A" << endl;
T & operator()(unsigned int rows, unsigned int colls); //cout << "B" << endl;
however, no matter which way I'm trying to call them only the second one is called:
int main()
{
Matrix<int> mat(2, 3);
mat(1, 1) = 3;
int i= (9 + mat(1, 1)) ;
i = mat(2, 1);
cout << i << endl;
if (i == mat(1, 2)) {}
int j = Matrix<int>(2, 2)(1, 1); //calls constructor and then subscription.
}
The output will be:
B
B
B
0
B
B
Good on the instructor for requesting operator(). There is hope for the universe.
This isn't so much of an rvalue/lvalue thing as it is constant/non constant.
The const on the end of the method definition states (and the compiler will do a and does a reasonable level checking that it won't) that calls to the method will not change the object's state. Absolutely necessary if you want to be able to call methods on a constant object.
If you add the following function to your test code:
void consttest(Matrix<int> &mat, const Matrix<int> &cmat)
{
mat(1,1) =4;
cmat(1,1) =4;
}
And call it like this:
consttest(mat, mat);
You'll see that good ol' rvalue/lvalue stuff in action. Sadly, you won't get to see your see your const operator() getting called because it won't compile. Pretty good test in it's own way, the method is guarded pretty well from mistakes, but a more useful test for functionality is:
void consttest(Matrix<int> &mat, const Matrix<int> &cmat)
{
std::cout << mat(1,2) << std::endl;
std::cout << cmat(1,2) << std::endl;
}
By the way, here's a nice chat on lvalues and rvalues: What are rvalues, lvalues, xvalues, glvalues, and prvalues?
I have inherited my class from std::vector. Now I want to overload the []-operator.
When I try to assign a new value to my vector, e.g. v[0]=5, I should receive the message OK.
This is my code (I know, that makes no sense, I'm just playing around):
#include<vector>
#include<iostream>
class Vec : public std::vector<int> {
public:
int operator[](int);
};
int Vec::operator[](int i) {
(*this)[i] = i;
std::cout << "OK";
return 123;
}
int main() {
Vec v;
v[0]=5;
}
Unfortunately I get the following error:
In member function ‘int Vec::operator[](int)’:
error: lvalue required as left operand of assignmen
In function ‘int main()’:
error: lvalue required as left operand of assignment
This particular error is caused because you are not returning an lvalue, generally defined as something that can appear to the left of an assignment, such as v[0] = 5;. You have more problems as pointed out in the other answers but this is the specific issue you face with that error message (a).
The correct specification for overloading the index operator is:
int& operator[] (const int nIndex);
You have to return a reference to the item (so it can be modified) if you want to treat it as an lvalue. The following code shows a fix, although obviously all array indexes map to the same value in this simplified case:
#include <vector>
#include <iostream>
class Vec : public std::vector<int> {
public:
int& operator[] (int); // <-- note the '&'
private:
int xyzzy;
};
int& Vec::operator[] (int idx) { // <-- note the '&'
std::cout << "OK\n";
return xyzzy;
}
int main () {
Vec v;
v[0] = 5;
v[1] = 6;
std::cout << v[22] << '\n';
return 0;
}
The output of this is:
OK
OK
OK
6
In reality, you wouldn't map all indexes to the same value, the code above is simply to illustrate the correct function signature. I haven't bothered to give a more complete example since subclassing classes with non-virtual destructors regularly leads to problems in non-trivial code (b).
(a) It's not usually considered a good idea to subclass std::vector since the destructor isn't virtual, so you can get into trouble when trying to destroy an object polymorphically.
You're probably better off using a has-a relationship (where your class contains a vector) rather than an is-a relationship (where you inherit).
That unfortunately means you may have to create a lot of pass-through methods from your class to the underlying vector (although only the ones you need) but it will solve the problem with the destructor.
(b) See (a) :-)
You'd need to return a reference to your element - however note that even if you did, you'd run into inifinite recursion - your operator[] calls itself.
Either way - inheriting from std::vector isn't a good idea. Use composition instead.
The code below illustrates how to call the operator[] from the vector base class....
#include <iostream>
#include <vector>
struct Vec : std::vector<int>
{
int& operator[](int n)
{
std::cout << "operator[](" << n << ")\n";
return std::vector<int>::operator[](n);
}
};
int main()
{
Vec v;
v.push_back(10);
v.push_back(20);
v[0] += 5;
std::cout << v[0] << ' ' << v[1] << '\n';
}
Output when I run it:
operator[](0)
operator[](1)
operator[](0)
15 20
Don't take all this talk about "do not inherit from std::vector" too seriously: you have to go out of your way to delete a dynamically allocated Vec using a std::vector<int>*, or do an accidental by-value slicing copy - and even then it'd probably only bite you if you had added data members. You should make sure you understand those risks then make your own assessment, but for small utility programs etc. it's productive to inherit from such classes sometimes....
This is a newbie C++ question. I was reading the "Function object" article in Wikipedia. The article has an example in C++ similar to the following:
struct printClass {
int &count;
printClass(int &n) : count(n) {}
void operator()(int &i) const {
count++;
cout << i << "[" << count << "] ";
}
};
int main(int argc, char** argv) {
vector<int> a(5, 7);
a[4] = -1;
a.resize(10, 3);
int state = 0;
for_each(a.rbegin(), a.rend(), printClass(state));
}
I have 2 questions:
Why does it fail to compile when count is a regular variable not a reference type? Demo
Why does it fail to compile it I change the ctor to the following? Demo
printClass(int &n) { count = n; }
Thanks.
EDIT: Thanks for explaining. I see that the following version works, too. Is there a reason for chosing one over another?
struct printClass {
int count;
printClass(int n) { count = n; }
void operator()(int &i) {
count++;
cout << i << "[" << count << "] ";
}
};
EDIT: Based on iammilind's reply, here is the 3rd version that works too using const_cast<int &>.
struct printClass {
int count ;
printClass(int n) : count(n) {}
void operator()(int &i) const {
const_cast<int &>(count)++;
cout << i << "[" << count << "] ";
}
};
(1) Why does it fail to compile when count is a regular variable not a
reference type?
This is a very interesting question. The question should be rather, why the code compiles when count is declared as a reference. :)
The regular variable fails because int count is not modifiable inside a const qualified function operator()(int &i) const;.
References are little different. In your code you are declaring the method as const, which means that count which is referring to i, now cannot refer to anything else.
But that's anyway not possible due to nature of references :). One cannot change reference binding after the initialization.
operator() just checks whether you are changing the binding of count to anything else or not? And the answer is always no. Because count++ changes the value referred by count and not the binding.
In your code, it doesn't matter if a member method is const or not when it comes to int& count.
Relate int& count; to int* const p_count; and try to simulate the situation on your own.
(2) Why does it fail to compile it I change the ctor to the following?
CountFrom(int &n) { count = n; }
Because reference must be assigned to a variable while initialization. In simple example;
int i, &r; // error, because 'r' not initialized
r = i; // this is not initialization but a copy
On a side note, you should be extra careful when you are dealing with reference variables inside a class. Because it's easy to mess up with their scope and validity.
For example, here the validity of count is dependent on the scope of i.
Edit: After your 2nd edit, it's very trivial to know why that version works.
Because count is now a simple variable. It can be skipped from initialization in the initializer list of the constructor unlike reference.
Moreover the const correctness of the operator() is gone, so any member variable of the class can now be modified inside it.
You should choose a const version of the member method, if you want to state that no class member "must" change inside it (unless any variable is mutable or you use const_cast). In all other cases use the normal version of the member method. They both can co-exist as well depending on your business logic. This is a bit of a broad question and it's worth to have another thread for this.