
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Extending Move Semantics To *this (Revision 1)</title>
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note {background-color:silver}
ins {color:red}
</style>
</head>

<body>

<address align=right>
Document number: N1821=05-0081<br>
Date: 2005-08-24<br>
Daveed Vandevoorde <a href="mailto:daveed@vandevoorde.com">
daveed@vandevoorde.com</a><br>
Bronek Kozicki <a href="mailto:brok@rubikon.pl">brok@rubikon.pl</a><br>
</address>
&nbsp;<br>
&nbsp;<br>
<h2>Extending Move Semantics To *this (Revision 1)</h2><br>
<h3>Introduction</h3>
<p>The <tt>this</tt> expression is really bound as a hidden <tt>*this</tt> parameter of reference type 
(WP 13.3.1/4). For example, a <tt>const</tt> member function of class <tt>X</tt> is a member 
function whose <tt>*this</tt> parameter has type <tt>X const&amp;</tt>. A special case overload 
resolution rule also specifies that <tt>non-const</tt> member functions can bind <tt>*this</tt>
to rvalues (even though the reference is otherwise an ordinary reference; WP 
13.3.1/5, 3<sup>rd</sup> bullet). This occasionally produces surprises.</p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1855.html">N1855</a> proposes the addition of &quot;rvalue-references&quot; (in addition to ordinary 
&quot;lvalue-references&quot;) in support of move semantics and perfect forwarding. However, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1855.html">N1855</a> 
does not extend the binding choice implied by the two distinct kinds of references to <tt>*this</tt>. 
This proposal endeavours to extend the binding choice to <tt>*this</tt>. Doing
so provides a mechanism to prevent the surprises alluded to, and also
extends the benefits of move semantics to the implicit <tt>*this</tt> parameter.</p>
<h3>Proposal (informal)</h3>
<p>Allow the following two overloadable member function forms:</p>
<blockquote><pre>
struct X {
    R f(...) cv &amp;;&nbsp;&nbsp; // Bind <b>*this</b> as an lvalue reference
    R f(...) cv &amp;&amp;;&nbsp; // Bind <b>*this</b> as an rvalue reference
};
</pre></blockquote>
<p>In either case, the <tt>*this</tt> parameter is bound exactly as an ordinary
parameter. The <tt>&amp;</tt> and <tt>&amp;&amp;</tt> suffixes are allowed only 
on members that allow a cv-qualifier in the same location (e.g., not 
constructors!). Additionally, neither of these forms can be overloaded with the 
existing form (the latter retains its binding semantics, including the exception that allows rvalues to be bound). Suffixes <tt>&amp;&amp;</tt> and <tt>&amp;</tt> affect the type of hidden <tt>*this</tt> object parameter, enabling overloading
based on lvalueness the target expression. For example:</p>
<blockquote><pre>
struct Y {
  R f(...);&nbsp;&nbsp;&nbsp;&nbsp;     // Okay
  R g(...) &amp;;&nbsp;&nbsp;     // Error: Cannot mix forms
  R g(...) const;&nbsp;  // Error: Cannot mix forms
  R h(...);&nbsp;&nbsp;&nbsp;&nbsp;     // Error: Cannot mix forms
  R h(...) &amp;&amp;;&nbsp;     // Error: Cannot mix forms
  R i(...) &amp;&amp;;&nbsp;     // Okay, hidden <b>*this</b> parameter will be Y&amp;&amp;
  R i(...) &amp;;&nbsp;&nbsp;     // Okay, hidden <b>*this</b> parameter will be Y&amp
  R i(...) const &amp;; // Okay, hidden <b>*this</b> parameter will be const Y&amp
  R j(...) &amp;;&nbsp;      // Okay, hidden <b>*this</b> parameter will be Y&amp
};
</pre></blockquote>
<h3>Examples</h3>
<p>Prevent surprises:</p>
<blockquote><pre>
struct S {
  S* operator &amp;() &amp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Selected for lvalues only
  S&amp; operator=(S const&amp;) &amp;;&nbsp;&nbsp;&nbsp;&nbsp; // Selected for lvalues only
};<br>
int main() {
  S* p = &amp;S();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Error!
  S() = S();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Error!
}<br>
</pre></blockquote>
<p>Enable move semantics:</p>
<blockquote><pre>
class X {
&nbsp;&nbsp; std::vector&lt;char&gt; data_;
public:
&nbsp;&nbsp; // ...
&nbsp;&nbsp; std::vector&lt;char&gt; const &amp; data() const &amp; { return data_; }
&nbsp;&nbsp; std::vector&lt;char&gt; &amp;&amp; data() &amp;&amp; { return data_; }
};

X f();

// ...
X x;
std::vector&lt;char&gt; a = x.data(); // copy
std::vector&lt;char&gt; b = f().data(); // move
</pre></blockquote>
<h3>Proposed wording (formal)</h3>
<i>As this proposal is based on rvalue-references proposal, following refers to wording proposed 
by document N1855, <b>not the current draft</b></i>
<h2>8 - Declarators</h2>
<p>...</p>
<p></ul></ol></dl><p><b>-4-</b> Declarators have the syntax</p>
<blockquote><pre>
declarator:
    direct-declarator
    ptr-operator declarator

direct-declarator:
    declarator-id
    direct-declarator ( parameter-declaration-clause ) cv-qualifier-seq<sub>opt</sub> exception-specification<sub>opt</sub>
    direct-declarator [ constant-expression<sub>opt</sub> ]
    ( declarator )

ptr-operator:
    * cv-qualifier-seq<sub>opt</sub>
    &
    &&
    ::<sub>opt</sub> nested-name-specifier * cv-qualifier-seq<sub>opt</sub>

cv-qualifier-seq:
    cv-qualifier cv-qualifier-seq<sub>opt</sub>
    <ins>& cv-qualifier-seq<sub>opt</sub></ins>
    <ins>&& cv-qualifier-seq<sub>opt</sub></ins>

</pre></blockquote>

<h3>8.3.5 - Functions [dcl.fct]</h3></a>
<p>...</p>
<p><b>-4-</b>
A
<i>cv-qualifier-seq</i>
shall only be part of the function type for a nonstatic member function,
the function type to which a pointer to member refers,
or the top-level function type of a function typedef declaration.
The effect of a
<i>cv-qualifier-seq</i>
in a function declarator is not the same as
adding cv-qualification on top of the function type, i.e., it does not
create a cv-qualified function type.
In fact, if at any time in the
determination of a type a cv-qualified function type is formed, the
program is ill-formed.
[<i>Example:</i>
<blockquote><tt><pre>
typedef void F();
struct S {
	const F f;              //</tt><i>  ill-formed:</i><tt>
				//</tt><i>  not equivalent to:  </i><tt>void</tt><i>   </i><tt>f()</tt><i>   </i><tt>const;
};
</pre></tt></blockquote>
<br>--- end example]
The return type, the parameter type list and the
<i>cv-qualifier-seq</i>,
but not the default arguments (dcl.fct.default)
<ins>, & lvalue-qualifier, && rvalue-qualifier (class.mfct.nonstatic)</ins>
or the exception specification (except.spec),
are part of the function type.
[<i>Note:</i>
function types are checked during the assignments and initializations of
pointer-to-functions, reference-to-functions, and pointer-to-member-functions.
]
</ul></ol></dl><h3>9.3.1 - Nonstatic member functions [class.mfct.nonstatic]</h3>
<p>...</p>
<p><b>-3-</b>
A nonstatic member function may be declared
<tt>const</tt>,
<tt>volatile</tt>,
or
<tt>const</tt>
<tt>volatile</tt>.
These
<i>cv-qualifiers</i>
affect the type of the
<tt>this</tt>
pointer (class.this).
They also affect the function type (dcl.fct) of the member function;
a member function declared
<tt>const</tt>
is a
<i>const</i>
member function, a member function declared
<tt>volatile</tt>
is a
<i>volatile</i>
member function and a member function declared
<tt>const</tt>
<tt>volatile</tt>
is a
<i>const</i>
<i>volatile</i>
member function.
[<i>Example:</i>
<blockquote><tt><pre>
struct X {
	void g() const;
	void h() const volatile;
};
</pre></tt></blockquote>
<tt>X::g</tt>
is a
<tt>const</tt>
member function and
<tt>X::h</tt>
is a
<tt>const</tt>
<tt>volatile</tt>
member function.
]
</ul></ol></dl><p><b>-4-</b>
A nonstatic member function may be declared
<i>virtual</i>
(class.virtual) or
<i>pure</i>
<i>virtual</i>
(class.abstract).
<ins>
</ul></ol></dl><p><b>-5-</b> A nonstatic member function may be qualified by 
one of <tt>&amp;&amp;</tt> rvalue-qualifier or <tt>&amp;</tt> lvalue-qualifier. These qualifiers affect the type
of implicit object parameter passed to non-static member functions (over.match.funcs)</ins><a name="over.load"><h2>
13.1 - Overloadable declarations [over.load]</h2>
</a>
<p>...</p>
<p><b>-2-</b> Certain function declarations cannot be overloaded: </p>
<ul>
	<li>Function declarations that differ only in the return type cannot be 
	overloaded. </li>
</ul>
<ul>
	<li>Member function declarations with the same name and the same parameter 
	types cannot be overloaded if any of them is a <tt>static</tt> member 
	function declaration (class.static). 
	Likewise, member function template declarations with the same name, the same 
	parameter types, and the same template parameter lists cannot be overloaded 
	if any of them is a <tt>static</tt> member function template declaration. 
	The types of the implicit object parameters constructed for the member 
	functions for the purpose of overload resolution (over.match.funcs) 
	are not considered when comparing parameter types for enforcement of this 
	rule. In contrast, if there is no <tt>static</tt> member function 
	declaration among a set of member function declarations with the same name 
	and the same parameter types, then these member function declarations can be 
	overloaded if they differ in the type of their implicit object parameter. [<i>Example:</i> 
	the following illustrates this distinction: 
	<blockquote>
		<tt>
		<pre>class X {
    static void f();
    void f();                   //</tt><i>  ill-formed</i><tt>
    void f() const;             //</tt><i>  ill-formed</i><tt>
    void f() const volatile;    //</tt><i>  ill-formed</i><tt>
    void g();
    void g() const;             //</tt><i>  OK: no static  </i><tt>g
    void g() const volatile;    //</tt><i>  OK: no static  </i><tt>g
};
</pre>
		</tt>
	</blockquote>
	<br>
	--- end example] </li>
</ul>
<ins><ul>
	<li>Set of non-static member functions that differ only in the type of their implicit object parameter may 
	be overloaded by rvalue-qualifier or lvalue-qualifier (class.mfct.nonstatic) only if all 
	functions in said set are qualified with these qualifiers.</li>
</ul></ins>


<h2>13.3.1 - Candidate functions and argument lists</h2>
<p>...</p>

<p>
<b>-4-</b> For non-static member functions, the type of the implicit object parameter 
is ``reference to <i>cv</i> <tt>X</tt>''<ins>, for non-static functions qualified
with <tt>&amp;&amp;</tt> rvalue-qualifier (class.mfct.nonstatic), the type of the implicit object 
parameter is ``rvalue-reference to <i>cv</i> <tt>X</tt>'', for non-static functions
qualified with <tt>&amp;</tt> lvalue-qualifier (class.mfct.nonstatic), the type of the implicit 
object parameter is ``lvalue-reference to <i>cv</i> <tt>X</tt>'',</ins> where 
<tt>X</tt> is the class of which 
the function is a member and <i>cv</i> is the cv-qualification on the member 
function declaration. [<i>Example:</i> for a <tt>const</tt> member function of 
class <tt>X</tt>, the extra parameter is assumed to have type ``reference to <tt>
const&nbsp;X</tt>''. ] For conversion functions, the function is considered to be a 
member of the class of the implicit object argument for the purpose of defining 
the type of the implicit object parameter. For non-conversion functions 
introduced by a <i>using-declaration</i> into a derived class, the function is 
considered to be a member of the derived class for the purpose of defining the 
type of the implicit object parameter. For static member functions, the implicit 
object parameter is considered to match any object (since if the function is 
selected, the object is discarded). [<i>Note:</i> no actual type is established 
for the implicit object parameter of a static member function, and no attempt 
will be made to determine a conversion sequence for that parameter (over.match.best).]
</p>
<p><b>-5-</b> During overload resolution, the implied object argument is 
indistinguishable from other arguments. The implicit object parameter, however, 
retains its identity since conversions on the corresponding argument shall obey 
these additional rules: </p>
<ul>
	<li>no temporary object can be introduced to hold the argument for the 
	implicit object parameter; and</li>
</ul>
<ul>
	<li>no user-defined conversions can be applied to achieve a type match with 
	it;</li>
</ul>
<ins>For non-static member functions which are not qualified with an rvalue-qualifier or lvalue-qualifier (class.mfct.nonstatic) additional rule applies:</ins> 
<ul>
	<li>even if the implicit object parameter is not <tt>const</tt>-qualified, 
	an rvalue temporary can be bound to the parameter as long as in all other 
	respects the temporary can be converted to the type of the implicit object 
	parameter. The rvalue-ness of said temporary does not impact the ranking of implicit conversion sequences (13.3.3.2).
	</li>
</ul>
<h2>13.3.3.2 Ranking implicit conversion sequences</h2>
<p>-3- Two implicit conversion sequences of the same form are indistinguishable 
conversion sequences unless one of the following rules apply: </p>
<p>...</p>
<ul>
	<li><tt>S1</tt> and <tt>S2</tt> differ only in their qualification 
	conversion and yield similar types <tt>T1</tt> and <tt>T2</tt> (conv.qual), 
	respectively, and the cv-qualification signature of type <tt>T1</tt> is a 
	proper subset of the cv-qualification signature of type <tt>T2</tt>, and <tt>
	S1</tt> is not the deprecated string literal array-to-pointer conversion 
	(conv.array). [<i>Example:</i>
	<blockquote>
		<pre>int f(const int *);
int f(int *);
int i;
int j = f(&amp;i);                  //  Calls  f(int   *)
</pre>
	</blockquote>
	--- end example] or, if not that, </li>
	<li><tt>S1</tt> and <tt>S2</tt> are reference bindings (dcl.init.ref) 
	and neither refers to an implicit object parameter <ins> of a non-static member function which is not qualified 
	with an lvalue-qualifier or rvalue-qualifier (class.mfct.nonstatic)</ins>, and <tt>S1</tt> binds an 
	lvalue-reference to an lvalue and <tt>S2</tt> does not bind an 
	lvalue-reference or <tt>S1</tt> binds an rvalue-reference to an rvalue and
	<tt>S2</tt> does not bind an rvalue-reference.<br>
	</li>
</ul>
	<p>...</p>

&nbsp;<br>
&nbsp;<br>
<h3>Acknowledgements</h3>
Many thanks to Howard Hinnant for help in all stages of this proposal and to 
Peter Dimov for motivating example
</body>

</html>