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 ]