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.
Related
We know that a "const variable" indicates that once assigned, you cannot change the variable, like this:
int const i = 1;
i = 2;
The program above will fail to compile; gcc prompts with an error:
assignment of read-only variable 'i'
No problem, I can understand it, but the following example is beyond my understanding:
#include<iostream>
using namespace std;
int main()
{
boolalpha(cout);
int const i = 1;
cout << is_const<decltype(i)>::value << endl;
int const &ri = i;
cout << is_const<decltype(ri)>::value << endl;
return 0;
}
It outputs
true
false
Weird. We know that once a reference is bound to a name/variable, we cannot change this binding, we change its bound object. So I suppose the type of ri should be the same as i: when i is an int const, why is ri not const?
This may seem counter-intuitive but I think the way to understand this is to realize that, in certain respects, references are treated syntactically like pointers.
This seems logical for a pointer:
int main()
{
boolalpha(cout);
int const i = 1;
cout << is_const<decltype(i)>::value << endl;
int const* ri = &i;
cout << is_const<decltype(ri)>::value << endl;
}
Output:
true
false
This is logical because we know it is not the pointer object that is const (it can be made to point elsewhere) it is the object that is being pointed to.
So we correctly see the constness of the pointer itself returned as false.
If we want to make the pointer itself const we have to say:
int main()
{
boolalpha(cout);
int const i = 1;
cout << is_const<decltype(i)>::value << endl;
int const* const ri = &i;
cout << is_const<decltype(ri)>::value << endl;
}
Output:
true
true
And so I think we see a syntactic analogy with the reference.
However references are semantically different to pointers especially in one crucial respect, we are not allowed to rebind a reference to another object once bound.
So even though references share the same syntax as pointers the rules are different and so the language prevents us from declaring the reference itself const like this:
int main()
{
boolalpha(cout);
int const i = 1;
cout << is_const<decltype(i)>::value << endl;
int const& const ri = i; // COMPILE TIME ERROR!
cout << is_const<decltype(ri)>::value << endl;
}
I assume we are not allowed to do this because it doesn't appear to be needed when the language rules prevent the reference from being rebound in the same way a pointer could(if it is not declared const).
So to answer the question:
Q) Why “reference” is not a “const” in C++?
In your example the syntax makes the thing being referred to const the same way it would if you were declaring a pointer.
Rightly or wrongly we are not allowed to make the reference itself const but if we were it would look like this:
int const& const ri = i; // not allowed
Q) we know once a reference is bind to a name/variable, we cannot change this binding, we change its binded object.
So I suppose the type of ri should be same as i: when i is a int const, why ri is not const?
Why is the decltype() not transferred to the object the referece is bound to?
I suppose this is for semantic equivalence with pointers and maybe also the function of decltype() (declared type) is to look back at what was declared before the binding took place.
why is "ri" not "const"?
std::is_const checks whether the type is const-qualified or not.
If T is a const-qualified type (that is, const, or const volatile), provides the member constant value equal true. For any other type, value is false.
But the reference can't be const-qualified. References [dcl.ref]/1
Cv-qualified references are ill-formed except when the cv-qualifiers
are introduced through the use of a typedef-name ([dcl.typedef],
[temp.param]) or decltype-specifier ([dcl.type.simple]), in which case
the cv-qualifiers are ignored.
So is_const<decltype(ri)>::value will return false becuase ri (the reference) is not a const-qualified type. As you said, we can't rebind a reference after initialization, which implies reference is always "const", on the other hand, const-qualified reference or const-unqualified reference might not make sense actually.
You need to use std::remove_reference for get the value you're looking for.
std::cout << std::is_const<std::remove_reference<decltype(ri)>::type>::value << std::endl;
For more information, see this post.
Why are macros not const? Functions? Literals? The names of types?
const things are only a subset of immutable things.
Since reference types are just that — types — it may have made some sense to require the const-qualifier on them all for symmetry with other types (particularly with pointer types), but this would get very tedious very quickly.
If C++ had immutable objects by default, requiring the mutable keyword on anything you didn't want to be const, then this would have been easy: simply don't allow programmers to add mutable to reference types.
As it is, they are immutable without qualification.
And, since they are not const-qualified, it would probably be more confusing for is_const on a reference type to yield true.
I find this to be a reasonable compromise, especially since the immutability is anyway enforced by the mere fact that no syntax exists to mutate a reference.
This is a quirk/feature in C++. Although we don't think of references as types, they in fact "sit" in the type system. Although this seems awkward (given that when references are used, the reference semantics occurs automatically and the reference "gets out of the way"), there are some defensible reasons why references are modeled in the type system instead of as a separate attribute outside of type.
Firstly, let us consider that not every attribute of a declared name must be in the type system. From the C language, we have "storage class", and "linkage". A name can be introduced as extern const int ri, where the extern indicates static storage class and the presence of linkage. The type is just const int.
C++ obviously embraces the notion that expressions have attributes that are outside of the type system. The language now has a concept of "value class" which is an attempt to organize the growing number of non-type attributes that an expression can exhibit.
Yet references are types. Why?
It used to be explained in C++ tutorials that a declaration like const int &ri introduced ri as having type const int, but reference semantics. That reference semantics was not a type; it was simply a kind of attribute indicating an unusual relationship between the name and the storage location. Furthermore, the fact that references are not types was used to rationalize why you cannot construct types based on references, even though the type construction syntax allows it. For instance, arrays or pointers to references not being possible: const int &ari[5] and const int &*pri.
But in fact references are types and so decltype(ri) retrieves some reference type node which is unqualified. You must descend past this node in the type tree to get to the underlying type with remove_reference.
When you use ri, the reference is transparently resolved, so that ri "looks and feels like i" and can be called an "alias" for it. In the type system, though, ri does in fact have a type which is "reference to const int".
Why are references types?
Consider that if references were not types, then these functions would be considered to have the same type:
void foo(int);
void foo(int &);
That simply cannot be for reasons which are pretty much self-evident. If they had the same type, that means either declaration would be suitable for either definition, and so every (int) function would have to be suspected of taking a reference.
Similarly, if references weren't types, then these two class declarations would be equivalent:
class foo {
int m;
};
class foo {
int &m;
};
It would be correct for one translation unit to use one declaration, and another translation unit in the same program to use the other declaration.
The fact is that a reference implies a difference in implementation and it is impossible to separate that from type, because type in C++ has to do with the implementation of an entity: its "layout" in bits so to speak. If two functions have the same type, they can be invoked with the same binary calling conventions: the ABI is the same. If two structs or classes have the same type, their layout is the same as well as the semantics of access to all the members. The presence of references changes these aspects of types, and so it's a straightforward design decision to incorporate them into the type system. (However, note a counterargument here: a struct/class member can be static, which also changes the representation; yet that isn't type!)
Thus, references are in the type system as "second class citizens" (not unlike functions and arrays in ISO C). There are certain things we cannot "do" with references, such as declare pointers to references, or arrays of them. But that doesn't mean they aren't types. They just aren't types in a way that it makes sense.
Not all these second-class-restrictions are essential. Given that there are structures of references, there could be arrays of references! E.g.
// fantasy syntax
int x = 0, y = 0;
int &ar[2] = { x, y };
// ar[0] is now an alias for x: could be useful!
This just isn't implemented in C++, that's all. Pointers to references do not make sense at all, though, because a pointer lifted from a reference just goes to the referenced object. The likely reason why there are no arrays of references is that the C++ people consider arrays to be a kind of low-level feature inherited from C that is broken in many ways that are irreparable, and they don't want to touch arrays as the basis for anything new. The existence of arrays of references, though, would make a clear example of how references have to be types.
Non-const-qualifiable types: found in ISO C90, too!
Some answers are hinting at the fact that references don't take a const qualifier. That is rather a red herring, because the declaration const int &ri = i isn't even attempting to make a const-qualified reference: it's a reference to a const-qualified type (which is itself not const). Just like const in *ri declares a pointer to something const, but that pointer is itself not const.
That said, it is true that references cannot carry the const qualifier themselves.
Yet, this is not so bizarre. Even in the ISO C 90 language, not all types can be const. Namely, arrays cannot be.
Firstly, the syntax doesn't exist for declaring a const array: int a const [42] is erroneous.
However, what the above declaration is trying to do can be expressed via an intermediate typedef:
typedef int array_t[42];
const array_t a;
But this doesn't do what it looks like it does. In this declaration, it is not a which gets const qualified, but the elements! That is to say, a[0] is a const int, but a is just "array of int". Consequently, this doesn't require a diagnostic:
int *p = a; /* surprise! */
This does:
a[0] = 1;
Again, this underscores the idea that references are in some sense "second class" in the type system, like arrays.
Note how the analogy holds even more deeply, since arrays also have an "invisible conversion behavior", like references. Without the programmer having to use any explicit operator, the identifier a automatically turns into an int * pointer, as if the expression &a[0] had been used. This is analogous to how a reference ri, when we use it as a primary expression, magically denotes the object i to which it is bound. It's just another "decay" like the "array to pointer decay".
And just like we must not become confused by the "array to pointer" decay into wrongly thinking that "arrays are just pointers in C and C++", we likewise mustn't think that references are just aliases that have no type of their own.
When decltype(ri) suppresses the usual conversion of the reference to its referent object, this is not so different from sizeof a suppressing the array-to-pointer conversion, and operating on the array type itself to calculate its size.
const X& x” means x aliases an X object, but you can’t change that X object via x.
And see std::is_const.
How do you define (explain) in a formal and strict way what is reference type in C++?
I tried to google, and looked into Stroustrup's "The C++ Programming Language", but I don't see definition of this concept there.
A reference is an alias, an alternate name for an object. It is not an object itself (and in that way is not a pointer, even if some of their uses overlap with uses of pointers).
References have certain limitations to their handling, related to their non-objectness. For example, you can't create an array of references. They have to be initialized (bound, seated) as soon as they are declared, since they can't possibly exist without an object to alias.
You can however store them, and they obey the rules of automatic variables or member variables. One of their uses is to poke through C++'s pass-by-value function calls.
Note that const references have a neat side-effect of being aliases : when bound to a temporary (i.e unnamed) object, they give said object a name, and therefore extend its lifetime to that of the reference itself.
{ // Block scope
Foo fooVal = makeFoo(); // Say makeFoo() returns a (temporary, unnamed) Foo
// Here the temporary Foo is dead (fooVal is a copy).
// Foo &fooRef = makeFoo(); // Error, reference is non-const
Foo const &fooCRef = makeFoo(); // All good
// ...
// The second temporary is still alive
fooCRef.doSomethingFunny(); // Works like a charm !
} // The second temporary dies with fooRef
Beware though, it is possible (though contrived) to have an object go out of scope with references still pointing to it. You will then have dangling references, which are not to be used anymore (doing so would be Undefined Behaviour).
Foo *fooPtr = new Foo; // Here is a Foo
Foo &fooRef = *fooPtr; // Here is an alias for that Foo
delete fooPtr; // Here is the end of that Foo's life
fooRef.doSomethingFunny(); // Here comes trouble...
Regarding
” How do you define (explain) in a formal and strict way what is reference type in C++?
the C++11 standard gives the following formal and strict definition of a reference type in its
§8.3.2/1
” In a declaration T D where D has either of the forms
& attribute-specifier-seqopt D1
&& attribute-specifier-seqopt D1
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T,” then the type of the
identifier of D is “derived-declarator-type-list reference to T.”
However, if you’re more interested in what a C++ reference practically is (apart from the colloquial use of the term), then check the definition of its meaning in an expression,
§5.5
” If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to
any further analysis. The expression designates the object or function denoted by the reference, and the
expression is an lvalue or an xvalue, depending on the expression
Effectively this means that a reference acts as an alias.
You can think of a reference as an automatically dereferenced const pointer, which explains most of the behavior except that a reference doesn't necessarily occupy storage (the compiler may be able to optimize it away completely).
According to some experts' views reference types are not C++ references per se, but in contrast to value types. I present two slightly differing definitions - of value types and of reference types.
https://abseil.io/blog/20180531-regular-types
The first is a blog post by Titus Winters, chair of the C++ subcommittee responsible for the C++ standards library.
According to Titus Winters, the difference between a value type and a reference type is the copy behaviour. When you copy an instance of a value type, you get two independent objects, which are equal first, but may differ after the modification of one of both. When you copy a reference type, you get two objects, which refer to the same data.
Reference types do not own their data. Some reference types allow modifying the referred-to data (e.g. span), some do not (e.g. string_view). Both examples given are quite useful for function parameter passing. The caller of the function assures (by convention) that the underlying data of the reference types is not destructed during the duration of the function call (as is also the case with plain C++ references).
https://learn.microsoft.com/en-us/cpp/cpp/value-types-modern-cpp?view=vs-2019
The Microsoft documentation puts reference types as synonymous to polymorphic types (types with at least one virtual function or member variable), and value types as non-polymorphic. (Non-polymorphic types are called concrete types by Bjarne Stroustrup.)
Value types are about memory and layout control, reference types are about identity.
Value types allow the compiler direct access to the members, reference types need an indirection due to runtime polymorphism.
Reference types according to Microsoft are non-copyable (to prevent slicing).
So the semantics differ, as Titus Winters defines reference types by their actual copy behaviour.
A major difference between C and C++ (other than Objects and Classes!) is references.
A reference is like a const pointer to a variable. Assigning a reference is a bit like using a pointer but with & not * and you don't need to difference. The difference is that you assign an address to a pointer but a variable to a reference variable.
The line below suggests that the value of a is copied into aref. But it is not, instead aref is a reference to the variable a. Once assigned, aref is the same as a. Any changes to aref are changes to a as example below shows
int & aref = a;
#include <stdio.h>
#include "stdafx.h"
int main()
{
int a=9;
int & aref = a;
a++;
cout << "The value of a is %i\n" << aref;
return 0;
}
Also remember that
A reference must always refer to something.NULLs are not allowed.
A reference must be initialized when it is created. An unassigned reference can not exist.
Once initialized, it cannot be changed to another variable.
If it help you please inform me, thanx
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.
What is the difference between:
const double& pi = 3.14;
and (no ampersand):
const double pi = 3.14;
They both seem to have the same L and R values so what is the difference?
For your particular example there's no difference.
And that means, no way to tell them apart, whatsoever.
However, since the first binds a reference to a temporary, when the type is of class type the temporary can be of a derived class, e.g. produced by a function! And it then has its destructor properly called at the end of the scope. This little el neato trick is used in ScopeGuard implementations (see the original ScopeGuard article in DDJ, by Petru Marginean and Andrei Alexandrescu -- Petru invented ScopeGuard and Andrei made a more general thing on top).
I once asked Bjarne Stroustrup, who created the C++ language, why the syntax in your first declaration is supported.
And his reply was that it was mostly to have uniform rules (i.e. to not make any special exception for local references as opposed to references as formal parameters). I think at that time neither of us were familiar with ScopeGuard. It's simple in retrospect, but it takes a mind like Petru's, or Andrei's, to come up with something like that! :-)
Cheers & hth.
The important difference with a reference is that a reference itself is inheritly constant. Once the reference itself has been initially assigned to a variable, it can not then reference another variable. All attempts to modify it will modify the variable it refers to. Given this, the const will mean that the reference is a reference to a const int.
const int A;
const int B;
const int& Reference = A;
Reference = B; // Error, the value of A can not be assigned, nor would this *ever* be able to make Reference refer to B.
You can also test this theory about a reference itself being constant like so:
const int& const Reference; // Should give a warning about the second const being redundant.
A bit of clarification about constant references, references and constants for doubles.
Reference
A reference refers to an existing an object and cannot be reseated. That is, once you declare (define) the reference, it will always refer to that item.
Constant Reference
The C++ language allows for declaring of a constant reference. This tells the compiler that the reference will not change. This may be redundant since references cannot be reseated. However, the language syntax allows it.
Constant
A constant is a value, and does not refer to anything.
Optimizations & Substitutions
The compiler is allowed to substitute (replace) a reference to an object, constant or literal with the corresponding object, constant or literal, provided that the compiler can guarantee that no write operations are performed to that object within the scope it is used in. This determination may become difficult when the reference is passed to methods or functions within that scope.
Specifying the const modifier to a reference will make the compiler's job easier for optimizing. The constant reference is a contract with the programmer and user that the reference will not be changed.
const double& is a reference to a constant double, the other one is a constant double. A reference is kind of a const pointer, a pointer that never changes.
In C++ the references are inherently const. Once they have been assigned you can not changes them. They must be both declared and initialized.
The reference isnt const only the value is const, so you should be able reassign referense, that means the following would be ok:
const double& pi = 3.14;
const double pi2 = 2.78;
pi = *(&pi2);
I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
No.
The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.
For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand
&(2 + 3); // ERROR, lvalue required
However, as we all know, a constant reference can be attached to a temporary object, as in
const int &ri = 2 + 3;
In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary
const int *pi = &ri;
with that pointer remaining perfectly valid as long as the temporary persists.
Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.
So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.
Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:
rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
temporaries are not expressions
For that reason, the question doesn't make sense.
A good example is the following code:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.
well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,
*(a temp pointer) = val;
I swear I used to use some compiler that would pass temp values to any function that took a reference,
so you could go:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.
int anotherFunc(const int & b);
anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.
if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.
An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.
Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.
Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
or
return MyClass( 3 ); // likely to directly initialize object in caller's frame
Edit: as for the question of whether there is any temporary object in those cases, §12.8/15 mentions
the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
which would indicate that there is a temporary object which may be identical with an lvalue.
It depends on what you consider a temporary variable is. You can write something like
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
This runs in VisualStudios and GCC. You can run the code in codepad
I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
The following code binds a constant reference to a temporary object of type const float created by the compiler:
int i;
const float &cfr = i;
The behaviour is "as if":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;