I was going over the following example
const int a = 12;
int b;
b = const_cast<int&>(a);
and I wanted to know what & in the template parameter type signifies above and why it wont work without the & ?
Update:
Let me rephrase my question . I understand its a reference but what variable is it referring to ? For instance here it states that incase of pointers it references the original (uncast) pointer. I want to know what it references incase of non pointer types and how can b b a reference when it wasnt declared as a reference ?
const_cast is not a template, but rather a type cast. What appears to be a template argument is the destination type for the cast, and in this case it means that you want to obtain a non-const reference to int that refers to the same objects as a.
a is const int& when you do the const_cast as you wrote it.
You can only modify cv-qualifiers of pointer and reference types with const_cast, not of values. This is because specifying constness for rvalues only makes sense if this is of reference or pointer type and can thus be modified.
So if you just want the (non-const) value of the variable a, simply write
b = a;
as the const-ness is ignored anyway. b is then copy-constructed from a.
Basically a is const, b is not const
so const_cast basically says b is stored at a but removes the const.
Related
The book said: Because references are not objects, we may not define a reference to a reference.
int ival = 1024;
int &refVal = ival;
refVal = 2;
int ii = refVal;
int &refVal3 = refVal; // isn't this a definition of ref to ref?
int i = refVal;
int &refVal4 = 10;
double dval = 3.14;
int &refVal5 = dval;
However, that line is not an error, because refVal3 is saying it is just another alias for refVal, and refVal is just another name for ival(refVal3 is bound to the object to which refVal is bound to, which is ival)... so both refVal and refVal3 refer to the initializer of ival.
That makes perfect sense, but if that's not a definition of a reference to a reference, just what exactly does the book mean when it mentioned "Because references are not objects, we may not define a reference to a reference." ??
Can someone perhaps give me an example ?
Your understanding is correct.
int &refVal3 = refVal;
This makes refVal3 a reference to the same thing refVal is a reference to. That is, ival.
just what exactly does the book mean when it mentioned "Because
references are not objects, we may not define a reference to a
reference." ?
A reference can only refer to an object. But references are not objects. So a reference cannot refer to a reference. And when the book says this, it doesn't just mean that it's not allowed, and you'll get an error if you try. But you can't even try. There's no syntax for it. Because anything you try to do to a reference, you will actually be doing to the object it refers to, and not to the reference itself.
Can someone perhaps give me an example ?
No. I can't. And that's the point. There's simply no syntax for it.
Reference-to-reference types (like T & &) do not exist in C++.
Where T is an object type (which includes int, as in your example):
You can have (lvalue) references to T. There exists a type T &.
You can have rvalue references to T. There exists a type T &&.
T && is not a reference to a reference; && is a single token and does not mean & &.
You cannot have references to references to T. There are no such types as T & &, T & &&, T && & or T && &&. If you write a declaration that attempts to explicitly name such a type, this is an error.
(Similarly, cv-qualified types like const T& exist, while types like const T & & do not exist.)
You asked for an example. Consider this wrong code:
int main()
{
int ival = 1024;
int &refVal = ival;
int & &refRefVal = refVal; // wrong
}
This is an error because there is no such type as int & &. It would be an error regardless of what I tried to initialize it with.
(Strictly speaking, it is an error because the syntax of the language prohibits it. The standards committee could have chosen to allow me to write int & & and have it mean the same thing as int &--see Reference Collapsing below--but they didn't, which is good, because that would be very confusing.)
When I attempt to compile that wrong code with Clang 3.8, I get:
error: 'refRefVal' declared as a reference to a reference
Other compilers give similar errors. For example, Microsoft Visual C++ gives:
error C2529: 'refRefVal': reference to reference is illegal
When you use a reference, the effect is to use the object it refers to.
References are dereferenced automatically in most contexts where they appear. Anything you try to do to a reference, really you are doing it to the object it refers to. Unlike pointers, there is no operator for dereferencing a reference; in effect the reference is a name for the referenced object.
What you have written (int &refVal3 = refVal;) is not an error, because you are simply initializing a second reference bound to the same object. To see why this is, consider the effect of several of your statements.
Here you create an int, initializing it with the value 1024:
int ival = 1024;
Here you make an lvalue reference, bound to that int object:
int &refVal = ival;
Here you assign 2 to the original int object, because refVal is used as the object to which it refers:
refVal = 2;
Here you create a second int object, initialized with the value of the original object, also because refVal is used as the object to which it refers:
int ii = refVal;
Here you make a second lvalue reference to the original object, also because refVal is used as the object to which it refers:
int &refVal3 = refVal;
Code that looks like it creates a second reference to the first one is, therefore, really creating a second reference to the original object.
This is to say that the reason int &refVal3 = refVal; introduces another reference to the original object--rather than attempting to create a reference to a reference--is that this is just another consequence of refVal being automatically taken to mean the int it refers to.
Reference Collapsing
You can't write types named like T & & yourself, but what about this?
using Ref = int&;
using RefRef = Ref&; // I named this poorly, it's not really a reference to a reference!
This causes the compiler to see that I am trying to make a type alias RefRef to be int& &. The compiler follows the rules of reference collapsing. It collapses the two references into one, so the effect is the same as if I had written:
using RefRef = int&;
This behavior is useful in situations that involve type deduction, such as with templates, both by allowing more code to compile and work as expected than otherwise would, and by facilitating perfect forwarding. (One might argue it also parallels what you observed--when you initialize references from references, you can still never get a reference to a reference, only to an object.)
In no case is there ever anything whose type is reference to reference. The C++ language simply does not have any such types.
Consider this code:
struct AA
{
int& rr;
};
Is there a way to obtain pointer (or maybe reference) to AA::rr in order to obtain this?
AA* aa;
auto mm = &AA::rr; // error: cannot create pointer to reference member ‘AA::rr’
aa ->* mm;
Also in gcc-7.0.1 decltype(AA::mm) is just int&. Is this according to the standard? And does this make sense?
EDIT
Sorry guys, I formulated the question not quite well. No complaints to the fact that references are not objects or that there is no such thing as pointer to a reference. The goal is quite selfish. Given struct AA { int& rr; }; I just want to have a function like this:
template < typename Class, typename Member >
void test(Member Class::*) { }
that when calling test(&AA::rr) I want Class to be AA and Member to be int& or int. So I don't even need the pointer itself but its type that will allow to retrieve the class type and the member type.
How to obtain pointer to reference (member)?
You cannot obtain a pointers to (or references to, or arrays of) references. There is no such type as "pointer to reference" in C++. This is because references are not required to have storage, so there might not even be an address where the reference is stored.
When you apply addressof operator on a reference, what you get is the address of the object that is referred to.
Picture speaks a thousand words
References doesn't really have a container in the memory, they serves more like an alias to the original variable, thus you cannot get pointer to reference because references doesn't have their own memory location.
However, you can get the address of reference, which is the variable it is referencing. In this example, if you cout &rx and &x, they are the same.
So probably you would want to get a pointer to the object it is referencing, rather than pointer to reference
Consider the following template class
template <typename T>
class A {
public:
virtual T const& getContent() = 0;
};
I derive this class using 'int*' as type 'T', as follows
class A1 : public A<int*> {
private:
int a;
public:
int* const& getContent() { return &a; }
};
I got the following warning: 'returning reference to local temporary object'.
Questions:
Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.
Yes.
You cannot ignore this warning. A.a exists, but that's not the issue. What you are returning is not a pointer to int, but a reference to a pointer to int, i.e. it is a double indirection. To be specific, a temporary int* was created inside getContent that pointed to A.a. A reference to that temporary was returned, and then the temporary was destroyed. Using the result of getContent will be undefined behavior.
The idiomatic way to handle this situation would typically be to store the member you are passing a const reference to. In other words, have a member int* a, and then simply return a in your function. Returning a const reference is a common way to expose the fully functionality of a data member without allowing the user of the class to mutate it, messing up your class' invariants.
This is incorrect:
T const& getContent() = 0;
You can do:
T const getContent() = 0;
int* const getContent() { return &a; }
First of all...
int* const&
Is the same as...
int *const&
Edit: Originally, I wrongly stated it was equivalent to const int*&. Sorry, that was my fault.
And, references to pointers are more "cumbersome" than pointer themselves (at least IMHO), don't you think so? There's a reason pointers and references shall never be mixed (unless it's a consecuence of template instantiation, of course)...
int const&*
This is impossible, invalid, and last but no least, insane. Although there's no practical way for references to be implemented other than by pointers, they are not objects, in the sense that they (themselves) don't have a sizeof that does not equals that of their referenced type, and the fact that they don't have address at all, at least as far as the Sacred Writings of N4296 are concerned.
But... pointers are objects! The expression &a returns a rvalue (that is basically an object without an address) of type int*. Now, the statement return &a; will take that value and wrap it up in a reference, because...
That's what the function return type expects.
The lifetime of an rvalue of type T can be extended by means of it being holded in a reference of type const T&. However, you can't use this to return references to temporary rvalues.
Now, because all this stuff implies that you're returning a reference to a temporary rvalue in an unallowed way, you where tempted and falled into Undefined Behaviour.
The solution? Simply don't use references to pointers at all in the first place...
int const *getContent() { return a; }
Or, if you prefer it, use references, but not pointers...
int const &getContent() { return *a; }
Now, to the questions!
*Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?*: Yes and no. It does instantiate such a temporary as explained above (but usually optimized away), but it's type is int*, not int *const, although the latter gets implicitly casted into the former.
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?: That depends on whether you would ignore a divide-by-zero warning.
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.: You may either use "cumbersome" pointers or "beatiful" references, see above.
I hope this has led some light on you!
I am getting this error "Non-const lvalue to type 'Cell' cannot bind to a temporary of type 'Cell *' with this code :
class RegionHolder
{
public:
RegionHolder(Region& Region1):m_RegionCellNOO(&(Region1.m_NOO))
~RegionHolder();
protected:
Cell & m_RegionCellNOO; // difference is here
};
but not with this one :
class RegionHolder
{
public:
RegionHolder(Region& Region1):m_RegionCellNOO(&(Region1.m_NOO))
~RegionHolder();
protected:
Cell * m_RegionCellNOO; // difference is here
};
I don't understand the problem and would really like to use references and not pointers.
Thanks
You forgot to show us the definition, but presumably Region1.m_NOO is an object of type Cell. Your first example is taking the address of it, and trying to use the resulting pointer to initialise a reference. References aren't initialised from pointers, but from the object itself:
RegionHolder(Region& Region1):m_RegionCellNOO(Region1.m_NOO) {}
// ^ no & ^^ don't forget that
There is one caveat with using references rather than pointers: they are not assignable, and so neither is your class. Often that's not a problem; but if you do need your class to be assignable, then you'll need to use a pointer instead.
The unary & operator gets a pointer to a variable. So, in C++ (as in C) a = &b gets a pointer to b and stores this value in a, so if b is of type int, a needs to be of type int*. Assignment to references, on the other hand, is implicit, so if a is of type int& you simply need to write a=b to make a a reference to b. So in your case, you need to rewrite your constructor as
RegionHolder(Region& Region1):m_RegionCellNOO(Region1.m_NOO) {}
However, I think you're better off using pointers than references here anyway and trying to use C++ without getting comfortable with pointers is a very bad idea. So I suggest you take the time to make yourself comfortable with using pointers instead of trying to avoid them.
It is not possible to assign an integer value to a reference variable directly, say like:
int &x=10; //not possible
Is there any other way we can modify this statement to make it possible?
But not like this:
int a=10;int &x=a;
This works fine. But I want some other way or modify a little bit my expression and make it work!
The reference as the name says has to reference to something. How do you want to assign a value to it if it doesn't reference anything?
The reason it doesn't work is because 10 is of the type "const int". You can turn that into a reference, but you can't make it non-const without violating some logic at the least.
const int &a = 10;
that'll work.
int &b = const_cast<int &>(static_cast<const int &>(10));
will also compile, but you can't modify b (as that would imply modifying the actual "10" value).
The crux is that 10 is a constant – somewhat obviously: you cannot change its value. But if you try to assign it to an int reference, this would mean that the value were modifiable: an int& is a modifiable value.
To make your statement work, you can use a const reference:
int const& x = 10;
But as “cnicutar” has mentioned in a comment, this is pretty useless; just assign the 10 to a plain int.
You can't bind a reference-to-nonconst to anything immutable.
The standard permits storing compile time constants in ROM (btw, attempting to modify const_cast<>ed compile time constants yields undefined behaviour)
This would basically strip of the const, even if the const is invisible, therefore subverting the whole const-correctness-thing
However, you can bind a reference-to-const to nearly everything, including temporaries:
GotW: A candidate for the most important const
Consider this a "feature".
References refer to objects (perhaps temporary objects), not to values. If you want to store a value somewhere, assign it to an object, not to a reference.
As a special case, const int &a = 10; initializes the reference a to refer to a temporary object with the value 10, and it extends the lifetime of that temporary to the end of the scope of a (12.2/5). That's pretty useless with an integer literal, but occasionally useful with objects of class type. Still, this does not assign an integer value to a reference. It creates a temporary, and binds a reference to the temporary.
in the C++0x, you can use int&& (rvalue references ), but this can be used as function parameter.