string literal is an lvalue; other literals are rvalues.

Discussion in 'C++' started by Steven T. Hatton, Apr 12, 2004.

  1. This is from the draft of the previous version of the Standard:

    http://www.kuzbass.ru:8086/docs/isocpp/expr.html

    2- A literal is a primary expression. Its type depends on its form
    (lex.literal). A string literal is an *lvalue*; all other literals are
    *rvalues*.

    -4- The operator :: followed by an identifier, a qualified-id, or an
    operator-function-id is a primary-expression. Its type is specified by the
    declaration of the identifier, qualified-id, or operator-function-id. The
    result is the entity denoted by the identifier, qualified-id, or
    operator-function-id. The result is an *lvalue* if the entity is a function
    or variable. The identifier, qualified-id, or operator-function-id shall
    have global namespace scope or be visible in global scope because of a
    using-directive (namespace.udir). [Note: the use of :: allows a type, an
    object, a function, an enumerator, or a namespace declared in the global
    namespace to be referred to even if its identifier has been hidden
    (basic.lookup.qual). ]

    As I understand the distinction between rvalue and lvalue, an lvalue *can*
    appear on the left side of an expression, whereas an rvalue can *only*
    appear on the right side. What I don't fully understand is

    1) who cares? What I mean to ask is, why is it so important to specify?

    I assume it's a way of defining the syntax rules by specifying that lvalues
    can go here, but not rvalues, etc. But this seems like the chicken and the
    egg almost. There is talk of lvalue to rvalue conversion in 4.1. Is that
    just a conceptual artifice, or something the compiler actually does?

    2) I'm not sure why a function or a string literal would be considered an
    lvalue.

    In the case of a function is it because it can be a standalone statement? Or
    is it because it can appear in a pure virtual declaration on the lefthand
    side of the '='?

    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 12, 2004
    #1
    1. Advertising

  2. * "Steven T. Hatton" <> schriebt:
    >
    > As I understand the distinction between rvalue and lvalue, an lvalue *can*
    > appear on the left side of an expression, whereas an rvalue can *only*
    > appear on the right side.


    If they're not part of expressions.

    Another more useful difference is that you can take the address of an lvalue,
    but not of an rvalue.

    An lvalue denotes a storage location, an rvalue denotes a value sans location,
    such as the int value 5.

    Thus, an rvalue cannot by itself appear on the left hand side in an
    assignment, and that's the basis of the terminology.

    But the terminology is a bit misleading: a const lvalue can't appear on the
    left hand side of an assignment, either (although what's there must be an
    lvalue).



    > What I don't fully understand is
    >
    > 1) who cares? What I mean to ask is, why is it so important to specify?


    A program that modified the value of 5, say, would be difficult to debug.


    > I assume it's a way of defining the syntax rules by specifying that lvalues
    > can go here, but not rvalues, etc. But this seems like the chicken and the
    > egg almost. There is talk of lvalue to rvalue conversion in 4.1. Is that
    > just a conceptual artifice, or something the compiler actually does?


    I think it's your job to quote the relevant passage in 4.1.

    Converting an lvalue to rvalue is often necessary. E.g. you can use an int
    variable wherever you can use an int value such as 5. The opposite conversion
    is of course not allowed; e.g. you cannot assign to the value 5.



    > 2) I'm not sure why a function or a string literal would be considered an
    > lvalue.


    Function: because you must be able to take its address in order to use
    function pointers.

    String literal: because early C did not have 'const', and so old C functions
    that take 'char*' as argument could not be called with literal strings as
    actual arguments if string literals were considered rvalues. However, that
    may still change. It's just an old compatibility feature on its way out.


    > In the case of a function is it because it can be a standalone statement? Or
    > is it because it can appear in a pure virtual declaration on the lefthand
    > side of the '='?


    No, see above.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Apr 12, 2004
    #2
    1. Advertising

  3. Alf P. Steinbach wrote:

    > * "Steven T. Hatton" <> schriebt:
    >>
    >> As I understand the distinction between rvalue and lvalue, an lvalue
    >> *can* appear on the left side of an expression, whereas an rvalue can
    >> *only* appear on the right side.

    >
    > If they're not part of expressions.
    >
    > Another more useful difference is that you can take the address of an
    > lvalue, but not of an rvalue.
    >
    > An lvalue denotes a storage location, an rvalue denotes a value sans
    > location, such as the int value 5.


    If I have a literal 5 in my source code it begins life as an ascii
    character. That is translated and used by the compiler. It is either
    consumed to produce a result that somehow makes its way into the runtime
    instance of the program, or it is directly inserted into the runtime. E.g.,

    const int x = 5 * 125; // 5 is consumed and forgotten

    const int y = 5; // 5 lives a long and significant life

    int f(const int& n){
    return 5 * n; // 5 has to stick around in the shadows somewhere
    }

    > Thus, an rvalue cannot by itself appear on the left hand side in an
    > assignment, and that's the basis of the terminology.
    >
    > But the terminology is a bit misleading: a const lvalue can't appear on
    > the left hand side of an assignment, either (although what's there must be
    > an lvalue).


    I guess some of the difficulty is that we are talking about two drastically
    different models of the same abstract problem space. One is the text-based
    source code, the other is the runtime representation of the program in
    storage. When I read your statement that const lvalue can't appear on the
    lefthand side of an assignment I thought I understood and agreed with it.
    Then I wrote the two examples above. Does this mean that x and y only
    become const lvalues after they are initialized (defined)?

    I will grant that I know of no way to specify the location of 5 in the
    functon f above, but it has to have some kind of representaton in runtime
    storage. I'm not sure if it would be categorize as an rvalue. I'm just
    using it to try to get an undstanding of what parts of the source code find
    their way into the runtime image, and how they are represented there.

    I believe I undstood this stuff about ten years ago.

    >
    >> What I don't fully understand is
    >>
    >> 1) who cares? What I mean to ask is, why is it so important to specify?

    >
    > A program that modified the value of 5, say, would be difficult to debug.


    Agreed. But I knew that before I knew it was called an rvalue.


    >> I assume it's a way of defining the syntax rules by specifying that
    >> lvalues
    >> can go here, but not rvalues, etc. But this seems like the chicken and
    >> the
    >> egg almost. There is talk of lvalue to rvalue conversion in 4.1. Is that
    >> just a conceptual artifice, or something the compiler actually does?

    >
    > I think it's your job to quote the relevant passage in 4.1.


    This is a better link than the one I posted previously in this thread:
    http://www.itga.com.au/~gnb/wp/cd2/

    4.1 Lvalue-to-rvalue conversion [conv.lval]

    1 An lvalue (_basic.lval_) of a non-function, non-array type T can be
    converted to an rvalue. If T is an incomplete type, a program that
    necessitates this conversion is ill-formed. If the object to which
    the lvalue refers is not an object of type T and is not an object of a
    type derived from T, or if the object is uninitialized, a program that
    necessitates this conversion has undefined behavior. If T is a non-
    class type, the type of the rvalue is the cv-unqualified version of T.
    Otherwise, the type of the rvalue is T. 1)

    2 The value contained in the object indicated by the lvalue is the
    rvalue result. When an lvalue-to-rvalue conversion occurs within the
    operand of sizeof (_expr.sizeof_) the value contained in the refer-
    enced object is not accessed, since that operator does not evaluate
    its operand.

    > Converting an lvalue to rvalue is often necessary. E.g. you can use an
    > int
    > variable wherever you can use an int value such as 5. The opposite
    > conversion is of course not allowed; e.g. you cannot assign to the value
    > 5.


    But to say an lvalue is converted to an rvalue doesn't mean much to me.
    Does something actually happen in the CPU to change the representation of
    the object? Also, if the rvalue /is/ an object, it has a storage location
    doesn't it?

    >> 2) I'm not sure why a function or a string literal would be considered an
    >> lvalue.

    >
    > Function: because you must be able to take its address in order to use
    > function pointers.
    >
    > String literal: because early C did not have 'const', and so old C
    > functions that take 'char*' as argument could not be called with literal
    > strings as
    > actual arguments if string literals were considered rvalues. However,
    > that
    > may still change. It's just an old compatibility feature on its way out.


    There's something I'm missing here. What is the difference in how the
    program represents and process the same object as an rvalue or an lvalue?

    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 12, 2004
    #3
  4. * "Steven T. Hatton" <> schriebt:
    > Alf P. Steinbach wrote:
    >
    > > * "Steven T. Hatton" <> schriebt:
    > >>
    > >> As I understand the distinction between rvalue and lvalue, an lvalue
    > >> *can* appear on the left side of an expression, whereas an rvalue can
    > >> *only* appear on the right side.

    > >
    > > If they're not part of expressions.
    > >
    > > Another more useful difference is that you can take the address of an
    > > lvalue, but not of an rvalue.
    > >
    > > An lvalue denotes a storage location, an rvalue denotes a value sans
    > > location, such as the int value 5.


    Oops, that was not general enough. The function


    std::string foo(){ return "Hey"; }


    returns an rvalue because a temporary object is an rvalue. You cannot take
    its address because conceptually it has no storage location. But in terms of
    machine code it really has, in this particular case, and if you then define


    void bar( std::string const& s ){ std::cout << &s << std::endl; }


    and call it like


    bar( foo() );


    that location may be used directly, and if so then 'bar' will display it
    (also the object may itself have a function that gives its address).

    No, one does not need to be stupid in order not to think of that.

    The exact rules for this are _very_ complicated & hazy, e.g. causing a problem
    in Andrei Alexandrescu's original Mojo design (which was reviewed by hundreds
    of people before one really smart fellow spotted the problem).

    On the other hand in ordinary programming the conceptual model is very simple
    and suffices.

    Think of an rvalue as the integer value 5, and that's all you need.


    > const int x = 5 * 125; // 5 is consumed and forgotten
    >
    > const int y = 5; // 5 lives a long and significant life
    >
    > int f(const int& n){
    > return 5 * n; // 5 has to stick around in the shadows somewhere
    > }
    >
    > Does this mean that x and y only
    > become const lvalues after they are initialized (defined)?


    Yes. They do not exist before their initializations. And initialization is
    not assignment, in spite of having nearly the same syntax.

    The reason for initialization not being assignment (in C++) is that
    initialization may have to construct an object from raw memory, whereas
    assignment must change an existing object, e.g. deallocate stuff.


    > But to say an lvalue is converted to an rvalue doesn't mean much to me.
    > Does something actually happen in the CPU to change the representation of
    > the object?


    It might. In the case of 'a = b + 1;' the lvalue 'b' may be converted to
    rvalue by loading the contents of &b into a processor register. For example.


    > Also, if the rvalue /is/ an object, it has a storage location doesn't it?


    See above. It may. But you cannot directly take the address of an rvalue,
    and you cannot for sure obtain that address unless it's an object that has
    a function that returns the address, and especially in the case of built-in
    types it may not really have a storage location except in the sense of perhaps
    being embedded in a machine code instruction, and for a typical optimizing
    compiler even that may not exist; the rvalue might exist only conceptually,
    which is much of the point.


    > There's something I'm missing here. What is the difference in how the
    > program represents and process the same object as an rvalue or an lvalue?


    The difference is in what the program text is allowed to do. E.g. you cannot
    change the value 5. And you cannot call non-const functions on rvalues.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Apr 12, 2004
    #4
  5. Steven T. Hatton

    Howard Guest

    "Steven T. Hatton" <> wrote in message
    news:...
    > Alf P. Steinbach wrote:
    >
    > > * "Steven T. Hatton" <> schriebt:
    > >>
    > >> As I understand the distinction between rvalue and lvalue, an lvalue
    > >> *can* appear on the left side of an expression, whereas an rvalue can
    > >> *only* appear on the right side.

    > >
    > > If they're not part of expressions.
    > >
    > > Another more useful difference is that you can take the address of an
    > > lvalue, but not of an rvalue.
    > >
    > > An lvalue denotes a storage location, an rvalue denotes a value sans
    > > location, such as the int value 5.

    >
    > If I have a literal 5 in my source code it begins life as an ascii
    > character. That is translated and used by the compiler. It is either
    > consumed to produce a result that somehow makes its way into the runtime
    > instance of the program, or it is directly inserted into the runtime.

    E.g.,
    >
    > const int x = 5 * 125; // 5 is consumed and forgotten
    >
    > const int y = 5; // 5 lives a long and significant life
    >
    > int f(const int& n){
    > return 5 * n; // 5 has to stick around in the shadows somewhere
    > }
    >
    > > Thus, an rvalue cannot by itself appear on the left hand side in an
    > > assignment, and that's the basis of the terminology.
    > >
    > > But the terminology is a bit misleading: a const lvalue can't appear on
    > > the left hand side of an assignment, either (although what's there must

    be
    > > an lvalue).

    >
    > I guess some of the difficulty is that we are talking about two

    drastically
    > different models of the same abstract problem space. One is the

    text-based
    > source code, the other is the runtime representation of the program in
    > storage. When I read your statement that const lvalue can't appear on the
    > lefthand side of an assignment I thought I understood and agreed with it.
    > Then I wrote the two examples above. Does this mean that x and y only
    > become const lvalues after they are initialized (defined)?
    >
    > I will grant that I know of no way to specify the location of 5 in the
    > functon f above, but it has to have some kind of representaton in runtime
    > storage. I'm not sure if it would be categorize as an rvalue. I'm just
    > using it to try to get an undstanding of what parts of the source code

    find
    > their way into the runtime image, and how they are represented there.
    >
    > I believe I undstood this stuff about ten years ago.
    >


    You're misunderstanding basic data storage concepts here. Having the
    constant value 5 in your source code may lead to also having that value in
    the compiled machine code, but it's in the *code*, not in a data location.
    It becomes just a part of the arguments to a machine code instruction.
    Variables, however, are given specific storage space, and the address of
    that space is then used as an argument to machine code instructions. (Of
    course, sometimes the storage is temporary, like a register, and in those
    cases the register name is used instead of an address.) Look at the
    assemble language generated by defining, initializing, and assigning
    variables in your program, and you'll get the picture. (But turn off
    optimizations, because a very small program may have too much of what you
    want to see optimized into register data.)

    -Howard
     
    Howard, Apr 12, 2004
    #5
  6. Steven T. Hatton

    David Harmon Guest

    On Mon, 12 Apr 2004 10:58:47 -0400 in comp.lang.c++, "Steven T. Hatton"
    <> wrote,
    >If I have a literal 5 in my source code it begins life as an ascii
    >character.


    That may be, but there is no requirement in C++ that the source
    character set in which your program is written is ASCII. The C++
    standard turns backflips to ensure that it does not specify more than is
    necessary for a proper implementation of C++, and thereby impose
    unnecessary restrictions on portability and efficiency. If you wish to
    think about standard portable C++, you must likewise abandon many
    assumptions about implementation.

    A good one to start with is guesswork about what things do or do not
    occupy what memory. Especially consts and temporaries.

    >E.g.,
    >
    >const int x = 5 * 125; // 5 is consumed and forgotten


    5 is neither consumed nor forgotten. 5 is eternal and unchanging.
    The 5 you know is the same one Euclid knew.

    But, C++ requires that the above has the same effect as
    const int x = 625;

    >const int y = 5; // 5 lives a long and significant life


    No, you are thinking of the lifetime of y. y is "alive" in whatever
    part of your program that declaration is visible. But y might never
    occupy run-time memory, if the generated code has no need to make it do
    so, ie. if you never take the address of y.

    >int f(const int& n){
    > return 5 * n; // 5 has to stick around in the shadows somewhere
    >}


    This might possibly for instance be implemented by something resembling
    return (n << 2) + n;

    >I will grant that I know of no way to specify the location of 5 in the
    >functon f above, but it has to have some kind of representaton in runtime
    >storage.


    I suppose the representation of 5 in runtime storage in ((n << 2) + n)
    is implicit in the sequence of some machine instructions in the
    generated code. It certainly does not _have to_ correspond to a
    location in memory with the value 5 in it, it is a rvalue.
    Is that what you are trying to say?
     
    David Harmon, Apr 12, 2004
    #6
  7. David Harmon wrote:

    > On Mon, 12 Apr 2004 10:58:47 -0400 in comp.lang.c++, "Steven T. Hatton"
    > <> wrote,
    >>If I have a literal 5 in my source code it begins life as an ascii
    >>character.

    >
    > That may be, but there is no requirement in C++ that the source
    > character set in which your program is written is ASCII. The C++
    > standard turns backflips to ensure that it does not specify more than is
    > necessary for a proper implementation of C++, and thereby impose
    > unnecessary restrictions on portability and efficiency.


    Just to be pedantic, the Standard /does/ specify that the basic source
    character set is a subset of the ASCII character set:

    15) The glyphs for the members of the basic source character set are
    intended to identify characters from the subset of ISO/IEC 10646 which
    corresponds to the ASCII character set.

    > If you wish to
    > think about standard portable C++, you must likewise abandon many
    > assumptions about implementation.
    >
    > A good one to start with is guesswork about what things do or do not
    > occupy what memory. Especially consts and temporaries.


    I don't believe it is really possible to comprehend the intent of the
    standard at that level of abstraction.

    >>E.g.,
    >>
    >>const int x = 5 * 125; // 5 is consumed and forgotten

    >
    > 5 is neither consumed nor forgotten. 5 is eternal and unchanging.
    > The 5 you know is the same one Euclid knew.


    Euclid knew about integer literals?

    > But, C++ requires that the above has the same effect as
    > const int x = 625;


    "5) This provision is sometimes called the as-if rule, because an
    implementation is free to disregard any requirement of this International
    Standard as long as the result is as if the requirement had been obeyed, as
    far as can be determined from the observable behavior of the program. For
    instance, an actual implementation need not evaluate part of an expression
    if it can deduce that its value is not used and that no side effects
    affecting the observable behavior of the program are produced."

    So, technically, I cannot speak in terms of what the implementation actually
    does and express the full intention of the Standard.

    >>const int y = 5; // 5 lives a long and significant life

    >
    > No, you are thinking of the lifetime of y. y is "alive" in whatever
    > part of your program that declaration is visible. But y might never
    > occupy run-time memory, if the generated code has no need to make it do
    > so, ie. if you never take the address of y.


    But, in some sense 5 is recoverable, whereas in the first example, it is
    not. I had implicitly assumed y was used.

    > This might possibly for instance be implemented by something resembling
    > return (n << 2) + n;


    Yes, I had considered that possibility.

    >>I will grant that I know of no way to specify the location of 5 in the
    >>functon f above, but it has to have some kind of representaton in runtime
    >>storage.

    >
    > I suppose the representation of 5 in runtime storage in ((n << 2) + n)
    > is implicit in the sequence of some machine instructions in the
    > generated code. It certainly does not _have to_ correspond to a
    > location in memory with the value 5 in it, it is a rvalue.
    > Is that what you are trying to say?


    No. " I'm not sure if it would be categorize as an rvalue. I'm just
    using it to try to get an understanding of what parts of the source code
    find their way into the runtime image, and how they are represented there."

    Please read the portions of the Standard I quoted above so you are aware of
    what I already know. That should help you in determining what parts of my
    posts are informally making assumptions such as, 'virtual functions are
    implemented using vtbls', or, 'excessive inclusion of unnecessary headers
    leads to slower compile times'.

    If it's not clear what assumptions I have made, please ask for
    clarification.
    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 12, 2004
    #7
  8. Howard wrote:


    > You're misunderstanding basic data storage concepts here. Having the
    > constant value 5 in your source code may lead to also having that value in
    > the compiled machine code, but it's in the *code*, not in a data location.


    One man's data is another man's instruction. ;-)

    > It becomes just a part of the arguments to a machine code instruction.


    Actually, I thought I was making the point, not missing it. I will admit I
    was not sure how exactly to express it.

    > Variables, however, are given specific storage space, and the address of
    > that space is then used as an argument to machine code instructions. (Of
    > course, sometimes the storage is temporary, like a register, and in those
    > cases the register name is used instead of an address.) Look at the
    > assemble language generated by defining, initializing, and assigning
    > variables in your program, and you'll get the picture. (But turn off
    > optimizations, because a very small program may have too much of what you
    > want to see optimized into register data.)


    That is very good advice. Thank you.
    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 12, 2004
    #8
  9. Alf P. Steinbach wrote:

    > returns an rvalue because a temporary object is an rvalue. You cannot
    > take
    > its address because conceptually it has no storage location. But in terms
    > of machine code it really has, in this particular case, and if you then
    > define



    I looked this up in Sebesta's _Concepts of Programming Languages_, and found
    that he rather bluntly says: "The address of a variable is sometimes called
    its l-value, and the value is sometimes called its r-value."

    My edition is older than this one:
    http://www.aw-bc.com/catalog/academic/product/0,4096,0321193628,00.html


    Then we have K&R: "An object is a manipulatable region of storage; an lvalue
    is an expression referring to an object....The name 'lvalue' comes from the
    assignment expression E1 = E2 in which the left operand E1 must be an
    lvalue expression."

    http://www.embedded.com/story/OEG20010518S0071

    > It might. In the case of 'a = b + 1;' the lvalue 'b' may be converted to
    > rvalue by loading the contents of &b into a processor register. For
    > example.


    That seems worth considering. But, if we have an lvalue and its contents
    are loaded into a register, but its existing storage is not released, then
    it didn't /become/ an rvalue, it spawned an rvalue. I think?

    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 13, 2004
    #9
  10. * "Steven T. Hatton" <> schriebt:
    >
    > That seems worth considering. But, if we have an lvalue and its contents
    > are loaded into a register, but its existing storage is not released, then
    > it didn't /become/ an rvalue, it spawned an rvalue. I think?


    Right.

    Perhaps you've been bitten by a misunderstanding I once had about
    "conversion".

    Saying "A is converted to B" is often just a way of saying "form B is computed
    from form A", and does not necessarily imply a replacement of A with B.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Apr 13, 2004
    #10
  11. Alf P. Steinbach wrote:

    > * "Steven T. Hatton" <> schriebt:
    >>
    >> That seems worth considering. But, if we have an lvalue and its
    >> contents are loaded into a register, but its existing storage is not
    >> released, then it didn't /become/ an rvalue, it spawned an rvalue. I
    >> think?

    >
    > Right.
    >
    > Perhaps you've been bitten by a misunderstanding I once had about
    > "conversion".


    Actually, I'm usually pretty aware of that notion. It's the whole
    philosophy of information verses material posession. I can give a person
    an idea, and still have it. Of course there are issues of relative
    advantage of not sharing you ideas or knowledge in order to maintain some
    kind of advantage. For the most part, that is simply contrary to my
    nature. But I digress...

    > Saying "A is converted to B" is often just a way of saying "form B is
    > computed from form A", and does not necessarily imply a replacement of A
    > with B.


    And when you do that a few million times, you end up with a whole bunch of
    wasted storage. Actually, as I understand things, destroying A on every
    calculation, is exactly what Mathematica does. The entire expression is
    transformed according to the rules it expresses, and it is placed in new
    storage. I really don't know the details, but that's what I understood
    fromm one knowlegible person's explanation. Interestingly, Mathematica is
    very much a form of self-referential metaprogramming.

    I just found this:

    "We can allocate and use "variables" that do not have names, and it is
    possible to assign to strange-looking expressions (e.g., *p[a+10]=7).
    Consequently, there is a need for a name for "something in memory." This is
    the simplest and most fundamental notion of an object. That is, an /object/
    is a contiguous region of storage; an /lvalue/ is an expression that refers
    to an object" - Bjarne Stroustrup TC++PL(SE)

    --
    STH
    Hatton's Law: "There is only One inviolable Law"
    KDevelop: http://www.kdevelop.org SuSE: http://www.suse.com
    Mozilla: http://www.mozilla.org
     
    Steven T. Hatton, Apr 17, 2004
    #11
  12. * (Alf P. Steinbach) schriebt:
    >
    > And you cannot call non-const functions on rvalues.


    Boink! That was the sound of hand against empty skull. Reading another
    thread it finally filtered up from my unconsciousness that what I wrote
    many days ago had to be (perhaps subtly) W R O N G.


    #include <iostream>

    struct X
    {
    int my;
    X(): my( 0 ) {};
    X& set( int x ){ my = x; return *this; }
    };

    X foo(){ return X(); }

    int main()
    {
    std::cout << foo().set( 1234 ).my << std::endl;
    }


    I think it's _best_ to not do such things, but that's far cry from 'cannot'.

    But before leaving this, perhaps best to check with the standard that foo()
    is really an rvalue. Let's see. Yep,


    §3.10/5 The result of calling a function that does not return a reference
    is an rvalue.


    Perhaps also best to check whether the result is well-defined. But that's not
    nearly as clear in the standard. It states


    §3.10/10 An lvalue for an object is necessary in order to modify the
    object except that an rvalue of class type can be used to modify
    its referent under certain circumstances. [Example: a member
    function called for an object (9.3) can modify the object]


    seemingly without further specifying the "certain circumstances", and


    §3.10/14 If an expression can be used to modify the object to which it
    refers, the expression is called modifiable. A program that
    attempts to modify an object through a nonmodifiable lvalue or
    rvalue expression is ill-formed.


    seemingly without defining "modifiable" -- two earlier paragraphs define
    pointers to functions and pointers to incomplete types as modifiable, but that
    does not include class types, and not other pointer types.

    I'm glad I'm not a lawyer.

    (E-mailed copy to Stephen in case he doesn't follow this thread anymore.
    Sorry for the mis-information.)

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Apr 20, 2004
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Goche
    Replies:
    8
    Views:
    16,504
  2. Replies:
    6
    Views:
    520
    Rolf Magnus
    Jun 8, 2005
  3. Kavya
    Replies:
    9
    Views:
    525
    Dik T. Winter
    Oct 28, 2006
  4. Replies:
    11
    Views:
    710
    James Kuyper
    Sep 22, 2008
  5. Julian Mehnle
    Replies:
    0
    Views:
    246
    Julian Mehnle
    Jul 17, 2003
Loading...

Share This Page