I think I may have come up with an example of rvalue of array type

后端 未结 2 1146
攒了一身酷
攒了一身酷 2020-12-16 00:52

C++03 §4.2 N°1:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer

相关标签:
2条回答
  • 2020-12-16 01:20

    Yes, you are correct. The expression is an rvalue of array type. This is not a defect - the committee knows about it, and it was also a common issue in C89, which only allows conversion to pointers for lvalues of array types. As a consequence, you could not index or dereference an array like f().a. C99 fixed this, and C++ does not have a problem with it.

    Note that whether or not it is an rvalue is independent to whether or not the expression denotes an object. C++03 accidentally omitted to say that an rvalue expression that is of array type denotes an object. This was fixed in C++0x by DR#450.

    (obviously appreciating that there are no rvalues of such)

    There are actually rvalues of function types. These occur for non-static member functions denoted by a class member access expression

    struct A { void f(); };
    
    /* A().f is an rvalue of type "void()" */
    int main() { A().f(); }
    
    0 讨论(0)
  • 2020-12-16 01:29

    The A is an rvalue. The array inside it isn't. Imagine the case in which you have a method chain on that temporary object - the variables within it live for more than one method call and return, and they may pass references (valid for the duration of the chain) to other functions. Those functions cannot know in advance that they shall be called upon an rvalue.

    In the latest version of the draft, you can overload functions on rvalue/lvalue *this. However, even then, an rvalue reference does not make the contents of what is referred to an rvalue, and I'm not entirely sure that ANY compiler currently supports this, and I know that MSVC doesn't.

    Infact, using decltype, you can determine easily that the compiler calls that array an lvalue.

    Consider:

    template<typename A, typename B> auto sum(A&& a, B&& b) -> decltype(std::forward<A>(a) + std::forward<B>(b)) {
        return std::forward<A>(a) + std::forward<B>(b);
    }
    

    That's what decltype was for, and it most definitely differentiates between lvalues and rvalues. Alternatively, consider this:

    int main()
    {
        auto var = f().a;
    }
    

    Var is an int*. That's an instant fail, since f().a immediately dies. Not sure of my immediate opinion on that, but it's certainly not valid for an rvalue.

    0 讨论(0)
提交回复
热议问题