Topic: Rvalue Reference question: Overloading on whether *this is an rvalue


Author: jgottman@carolina.rr.com ("Joe Gottman")
Date: Fri, 24 Sep 2004 16:49:02 GMT
Raw View
   I have a question about that rvalue reference proposal in the pre-Redmond
mailing
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html).  Is
there any way to overload a member function on whether *this is an lvalue or
an rvalue?  Consider the following code:

    #include <vector>
    #include <string>

     vector<string> createVector();

     int main() {
        vector<string> v(1, "Hello World");
        std::string s1 = v[0];
       std::string s2 = createVector()[0];
       return 1;
}

Since v is an lvalue, s1 has to be created using a copy constructor.
However, since the result of createVector() is an rvalue, theoretically s2
could be created using a move constructor, thus saving the cost of copying
the string. Unfortunately, there seems to be no way to define a member
function that is overloaded on whether *this is an lvalue or an rvalue.  For
a non-member function, we can define an overload set as follows:

    string  const &getElement(vector<string> const &v, size_t index);
//const lvalues
    string &getElement(vector<string> &v, size_t index); // non-const
lvalues
    string &&getElement(vector<string> &&v, size_t index); //non-const
rvalues

It would be nice if we could do the same thing for member functions

template <class T, class A>
class vector {
        ...
        T const & operator[](size_t index) const;
        T & operator[](size_t index);
        T && operator[](size_t index) &&;  //Use && at end to say *this is
an rvalue reference, similar to const at end on the first function.
};

   The third function above would be illegal under the rvalue-reference
proposal in its current form, but I think it should be possible to do
something like this.

Joe Gottman

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 24 Sep 2004 17:55:56 GMT
Raw View
jgottman@carolina.rr.com ("Joe Gottman") writes:

>    I have a question about that rvalue reference proposal in the pre-Redmond
> mailing
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html).  Is
> there any way to overload a member function on whether *this is an lvalue or
> an rvalue?

No.  *some_pointer is always an lvalue.

> Consider the following code:
>
>     #include <vector>
>     #include <string>
>
>      vector<string> createVector();
>
>      int main() {
>         vector<string> v(1, "Hello World");
>         std::string s1 = v[0];
>        std::string s2 = createVector()[0];
>        return 1;
> }
>
> Since v is an lvalue, s1 has to be created using a copy constructor.
> However, since the result of createVector() is an rvalue, theoretically s2
> could be created using a move constructor, thus saving the cost of copying
> the string. Unfortunately, there seems to be no way to define a member
> function that is overloaded on whether *this is an lvalue or an rvalue.  For
> a non-member function, we can define an overload set as follows:
>
>     string  const &getElement(vector<string> const &v, size_t index);
> //const lvalues
>     string &getElement(vector<string> &v, size_t index); // non-const
> lvalues
>     string &&getElement(vector<string> &&v, size_t index); //non-const
> rvalues
>
> It would be nice if we could do the same thing for member functions
>
> template <class T, class A>
> class vector {
>         ...
>         T const & operator[](size_t index) const;
>         T & operator[](size_t index);
>         T && operator[](size_t index) &&;  //Use && at end to say *this is
> an rvalue reference, similar to const at end on the first function.
> };
>
>    The third function above would be illegal under the rvalue-reference
> proposal in its current form, but I think it should be possible to do
> something like this.

Hmm.  I don't love the syntax, though I agree for symmetry's sake
something like that should be possible.  I also think allowing
operator[] to be a non-member is probably a good idea.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hinnant@metrowerks.com (Howard Hinnant)
Date: Fri, 24 Sep 2004 17:56:07 GMT
Raw View
In article <JaK4d.7177$zA3.1500343@twister.southeast.rr.com>,
 jgottman@carolina.rr.com ("Joe Gottman") wrote:

>    I have a question about that rvalue reference proposal in the pre-Redmond
> mailing
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html).  Is
> there any way to overload a member function on whether *this is an lvalue or
> an rvalue?  Consider the following code:
>
>     #include <vector>
>     #include <string>
>
>      vector<string> createVector();
>
>      int main() {
>         vector<string> v(1, "Hello World");
>         std::string s1 = v[0];
>        std::string s2 = createVector()[0];
>        return 1;
> }
>
> Since v is an lvalue, s1 has to be created using a copy constructor.
> However, since the result of createVector() is an rvalue, theoretically s2
> could be created using a move constructor, thus saving the cost of copying
> the string. Unfortunately, there seems to be no way to define a member
> function that is overloaded on whether *this is an lvalue or an rvalue.  For
> a non-member function, we can define an overload set as follows:
>
>     string  const &getElement(vector<string> const &v, size_t index);
> //const lvalues
>     string &getElement(vector<string> &v, size_t index); // non-const
> lvalues
>     string &&getElement(vector<string> &&v, size_t index); //non-const
> rvalues
>
> It would be nice if we could do the same thing for member functions
>
> template <class T, class A>
> class vector {
>         ...
>         T const & operator[](size_t index) const;
>         T & operator[](size_t index);
>         T && operator[](size_t index) &&;  //Use && at end to say *this is
> an rvalue reference, similar to const at end on the first function.
> };
>
>    The third function above would be illegal under the rvalue-reference
> proposal in its current form, but I think it should be possible to do
> something like this.

That's an interesting suggestion.  Section 13.3.1, in describing
overload resolution and member functions, describes member functions as
having an implicit object parameter with type cv X&, except that it will
also bind to rvalue X even if cv does not contain const.  In other
words, C++98, rewritten with the syntax, but not the capabilities of
N1690, says that member functions are transformed into the following for
the purpose of overload resolution:

class X
{
    R f(A1, A2, ...);
};

R X::f(A1, A2, ...);

becomes:

R f(X&&, A1, A2, ...);  // C++98

I.e. the X&& already exists in C++98, but is only available to the
compiler, and only in the context of binding the implicit object
parameter.

Your suggestion would require a way to overload on the implicit object
parameter with respect to lvalue/rvalue (we already can with respect to
cv qualifiers).  The ironic part is that in C++98, there is currently no
way to specify an implicit object parameter with an lvalue reference! :-)

R f(X&, A1, A2, ...);  // not doable in C++98!

I believe the trick in implementing your suggestion is to figure out how
to allow the above pseudo signature without breaking backward
compatibility.

Getting back to your example:

        T &  operator[](size_t index);     // 1
        T && operator[](size_t index) &&;  // 2

We have 2 today (except of course for the return type), and 1 is really
what you're requesting.  Therefore in the interest of backwards
compatibility the syntax would have to look something like:

        T &  operator[](size_t index) &; // 1
        T && operator[](size_t index);   // 2

Although I suppose we could put the decoration on 2, but tell the
compiler to vary the implicit object parameter on the undecorated 1
according to whether or not the decorated 2 actually existed in the
overload set.  Whether or not that is too complicated for the compiler,
I'm not in a position to say.

I'm stopping short of actually recommending such a proposal (nor do I
oppose it).  My post is merely meant to clarify what the situation is.

If overloading on the implicit object parameter rvalue/lvalue-ness is
not deemed practical, the client can still force the issue:

    std::string s2 = move(createVector()[0]);

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]