came across proposal called "rvalue reference *this" in clang's c++11 status page.
i've read quite bit rvalue references , understood them, don't think know this. couldn't find resources on web using terms.
there's link proposal paper on page: n2439 (extending move semantics *this), i'm not getting examples there.
what feature about?
first, "ref-qualifiers *this" "marketing statement". type of *this
never changes, see bottom of post. it's way easier understand wording though.
next, following code chooses function called based on ref-qualifier of "implicit object parameter" of function†:
// t.cpp #include <iostream> struct test{ void f() &{ std::cout << "lvalue object\n"; } void f() &&{ std::cout << "rvalue object\n"; } }; int main(){ test t; t.f(); // lvalue test().f(); // rvalue }
output:
$ clang++ -std=c++0x -stdlib=libc++ -wall -pedantic t.cpp $ ./a.out lvalue object rvalue object
the whole thing done allow take advantage of fact when object function called on rvalue (unnamed temporary, example). take following code further example:
struct test2{ std::unique_ptr<int[]> heavy_resource; test2() : heavy_resource(new int[500]) {} operator std::unique_ptr<int[]>() const&{ // lvalue object, deep copy std::unique_ptr<int[]> p(new int[500]); for(int i=0; < 500; ++i) p[i] = heavy_resource[i]; return p; } operator std::unique_ptr<int[]>() &&{ // rvalue object // garbage anyways, move resource return std::move(heavy_resource); } };
this may bit contrived, should idea.
note can combine cv-qualifiers (const
, volatile
) , ref-qualifiers (&
, &&
).
note: many standard quotes , overload resolution explanation after here!
† understand how works, , why @nicol bolas' answer @ least partly wrong, have dig in c++ standard bit (the part explaining why @nicol's answer wrong @ bottom, if you're interested in that).
which function going called determined process called overload resolution. process complicated, we'll touch bit important us.
first, it's important see how overload resolution member functions works:
§13.3.1 [over.match.funcs]
p2 set of candidate functions can contain both member , non-member functions resolved against same argument list. argument , parameter lists comparable within heterogeneous set, a member function considered have parameter, called implicit object parameter, represents object member function has been called. [...]
p3 similarly, when appropriate, context can construct argument list contains implied object argument denote object operated on.
why need compare member , non-member functions? operator overloading, that's why. consider this:
struct foo{ foo& operator<<(void*); // implementation unimportant }; foo& operator<<(foo&, char const*); // implementation unimportant
you'd want following call free function, don't you?
char const* s = "free foo!\n"; foo f; f << s;
that's why member , non-member functions included in so-called overload-set. make resolution less complicated, bold part of standard quote exists. additionally, important bit (same clause):
p4 non-static member functions, type of implicit object parameter is
“lvalue reference cv
x
” functions declared without ref-qualifier or&
ref-qualifier“rvalue reference cv
x
” functions declared&&
ref-qualifierwhere
x
class of function member , cv cv-qualification on member function declaration. [...]p5 during overload resolution [...] [t]he implicit object parameter [...] retains identity since conversions on corresponding argument shall obey these additional rules:
no temporary object can introduced hold argument implicit object parameter; and
no user-defined conversions can applied achieve type match it
[...]
(the last bit means can't cheat overload resolution based on implicit conversions of object member function (or operator) called on.)
let's take first example @ top of post. after aforementioned transformation, overload-set looks this:
void f1(test&); // match lvalues, linked 'void test::f() &' void f2(test&&); // match rvalues, linked 'void test::f() &&'
then argument list, containing implied object argument, matched against parameter-list of every function contained in overload-set. in our case, argument list contain object argument. let's see how looks like:
// first call 'f' in 'main' test t; f1(t); // 't' (lvalue) can match 'test&' (lvalue reference) // kept in overload-set f2(t); // 't' not rvalue, can't match 'test&&' (rvalue reference) // taken out of overload-set
if, after overloads in set tested, 1 remains, overload resolution succeeded , function linked transformed overload called. same goes second call 'f':
// second call 'f' in 'main' f1(test()); // 'test()' not lvalue, can't match 'test&' (lvalue reference) // taken out of overload-set f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference) // kept in overload-set
note that, had not provided ref-qualifier (and such not overloaded function), f1
would match rvalue (still §13.3.1
):
p5 [...] non-static member functions declared without ref-qualifier, additional rule applies:
- even if implicit object parameter not
const
-qualified, rvalue can bound parameter long in other respects argument can converted type of implicit object parameter.
struct test{ void f() { std::cout << "lvalue or rvalue object\n"; } }; int main(){ test t; t.f(); // ok test().f(); // ok }
now, onto why @nicol's answer atleast partly wrong. says:
note declaration changes type of
*this
.
that wrong, *this
always lvalue:
§5.3.1 [expr.unary.op] p1
the unary
*
operator performs indirection: expression applied shall pointer object type, or pointer function type and result lvalue referring object or function expression points.
§9.3.2 [class.this] p1
in body of non-static (9.3) member function, keyword
this
prvalue expression value address of object function called. type ofthis
in member function of classx
x*
. [...]
Comments
Post a Comment