<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<meta name="author" content="Bronislaw Kozicki">
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<title>Non-member overloaded copy assignment operator (J16/04-0116 = WG21/N1676)</title>
<style type="text/css">
 body {
  background-color: white;
 }
 p.c2 {margin-left:36.0pt;text-indent:-36.0pt;}
 h1.c1 {font-weight: bold}
</style>
</head>

<body lang="EN">

<h1 class="c1">Non-member overloaded copy assignment operator</h1>
<tt>
Doc. no.:&nbsp;J16/04-0116= WG21/N1676<br>
Date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9 September 2004<br>
Project:&nbsp;&nbsp;Programming Language C++<br>
Reply To:&nbsp;Bronek Kozicki &lt;<a href="mailto:brok@rubikon.pl">brok@rubikon.pl</a>&gt;<br>
</tt>
<h1 class="c1">Contents</h1>
<p><u><a href="#motivation">1. Motivation</a><br>
<a href="#design">2. Design and requirements</a><br>
<a href="#proposal">3. Proposal</a><br>
&nbsp; <a href="#explicit_only">3.1 Only explicit classes</a><br>
&nbsp; <a href="#non_implicit">3.2 Only classes where implicit copy assignment operator is not available</a><br>
&nbsp; <a href="#inside_class">3.3 Declaration only within class definition</a><br>
<a href="#discussion">4. Discussion</a><br>
&nbsp; <a href="#alternatives">4.1 Alternative solution</a></u></p>

<h2><a name="motivation"></a> 1.  Motivation</h2>
<p>Currently C++ Standard does not allow overloading of copy assignment operator as non-member
function; overloaded assignment operator must be member function of user defined
class. For this reason it&#39;s currently impossible to overload assignment operator
to make it behave like assignment operator for built-in type. Overloaded assignment
operator, like any other member function, may be called on rvalue (if accessible in place
of call), while assignment operator for built-in type may not be called on rvalue.
Ability to use only lvalue on left side of assignment operator is considered
important feature of language, however for many programmers it's not obvious that this
feature is provided only for built-in types. Following code demonstrates situation where this discrepancy is disturbing - program
behaves against programmer&#39;s expectations:</p>
<blockquote>
	<pre>#include &lt;cstdio&gt;

// some calculation goes here
int calc(int v)
{
  return v * 2;
}

template &lt;typename T, typename V&gt;
void f(T t, V v)
{
  // perform some calculation and
  // store result into reference returned by t()
  t() = calc(v);
}

class M
{
  struct K
  {
    int i;
    K(int i) : i (i) {}
  };
  // unable to disable assignment to rvalue of type K

  static K i;

public:
  static K&amp; g1()
  {
    return i;
  }

  static K g2()
  {
    return i; // returning copy!
  }

  static int&amp; g3()
  {
    return i.i;
  }

  static float g4()
  {
    return i.i; // returning copy!
  }

  static void show()
  {
    std::printf(&quot;K::i.i == %i\n&quot;, i.i);
  }
};

M::K M::i(1);

int main()
{
  f(M::g1, 30);    // OK
  M::show();       // 60

  f(M::g2, 31);    // should be an error, but compiles fine
  M::show();       // 60, which is unexpected output

  f(M::g3, 32);    // OK
  M::show();       // 64
  // n.f(M::g4, 34.43);    // error, as it should be
}

</pre>
</blockquote>
<p>Following proposal is an attempt to remove this inconsistency in the C++
programming language.</p>
<h2>
<a name="design">
</a>2. Design and requirements</h2>
<p>Proposed solution is to allow declaration of overloaded copy assignment operator
as a non-member function, with certain limitations. Such overloaded assignment operator
must accept two formal parameters. If left parameter is non-<tt>const</tt> reference,
only lvalue may be passed as left operand of assignment expression. Declaration
of overloaded assignment operator being non-member function might be template function,
there might be also many declarations with the same type of left operand (i.e. set
of overloaded functions). Following sections of this document will discuss proposed changes in
the C++ Standard,
limitations required to make these changes cooperate well with existing C++ features
and impact of proposed solution. Different solution is presented at the end of
this document.</p>
<h2> <a name="proposal"></a>3. Proposal </h2>
<p>Copy assignment operator for user defined class is always declared if object
of given class is being assigned some value - overloaded by programmer,
or implicitly declared by compiler (unless proposal
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1582.pdf">N1582</a>
<a href="#_5._References">[1]</a> is accepted). If programmer is allowed to declare
overloaded assignment operator as non-member function, program might have many assignment operators
for given class declared in different places:</p>
<ol>
<li>&nbsp; member functions declared inside class definition (overloaded or
declared implicitly by compiler), as currently allowed by the C++ Standard</li>
<li>&nbsp; non-member functions declared inside class definition (<tt>friend</tt>
functions)</li>
<li>&nbsp; non-member functions declared outside class definition</li>
</ol>
<p>We should remember that non-member function can be introduced at any place of
program, which means that if above is accepted as it is, actual user of class might
be able to declare copy assignment operator. This could introduce problems that
are hard to find and diagnose. Author presumes that members of the C++ Standard
Committee would be reluctant to allow it. Following sections will discuss limitations
that are proposed to remove this problem.</p>
<h3>
<a name="explicit_only">
</a>3.1  Only explicit classes</h3>
<p>If proposal N1582
is accepted, programmers will be able to define class without copy assignment
operator implicitly declared by compiler. It seems reasonable to allow
declaration of copy assignment operator for such class as desired by programmer,
be it member or non-member function. Thus one proposed limitation is to allow
overloading of copy assignment operator in form of non-member function only for
<tt>explicit</tt> classes, as proposed in N1582. If type of left parameter of overloaded non-member copy assignment is
not reference to <tt>explicit</tt> class, program is ill-formed. This limitation will <em>
not</em> disallow declaration of overloaded copy assignment operator being
non-member function of class at any point of program (also by class user).</p>
<p>If proposed change with this limitation is accepted, following code will be well
formed:</p>
<blockquote>
	<pre>explicit struct K
{
  int i;
  K&amp; operator= (double);
};

K&amp; operator=(K&amp;, const K&amp;);
K&amp; operator=(K&amp;, int);
</pre>
</blockquote>

<h3><a name="non_implicit"></a>3.2 Only classes where implicit copy assignment operator
is not available</h3>
<p>In some cases (specified in clause 12.8/12 of the C++ Standard) program is ill-formed if
copy assignment operator implicitly declared by compiler is being used. In other
words, for some user defined classes implicitly declared copy assignment is not
available. This is actually similar to <tt>explicit</tt> class, as specified in
N1582. Thus alternatively to limitation described above (section 3.1), it might
be possible to allow declaration of overloaded copy assignment as non-member for
all classes where implicitly declared copy assignment is not available - per
clause of 12.8/12 the C++ Standard or due to <tt>explicit</tt> class qualifier
proposed in N1582. This limitation will <em>
not</em> disallow declaration of overloaded copy assignment operator being
non-member function of class at any point of program.</p>
<p> If proposed change with this limitation is accepted, following code will be well
formed:</p>
<blockquote>
	<pre>struct K
{
  const int i;
  K() : i(0) {}
};

K&amp; operator=(K&amp;, const K&amp;);
</pre>
</blockquote>



<h3>
<a name="inside_class">
</a>3.3 Declaration only within class definition</h3>
<p>Another proposed limitation is to allow declaration of overloaded non-member copy assignment operator
only inside definition of class. Currently only one form of declaration of non-member
function inside definition of class is allowed, that is <tt>friend</tt> function. If type
of left parameter of overloaded non-member copy assignment operator is not reference
to class where overloaded operator is declared, program is ill-formed. This will
disallow declaration of non-member copy assignment at any point of program outside
class definition; it will also retain one important feature of overloaded copy assignment
- currently it is part of class interface <em>and</em> implementation. Author believes
that this limitation alone (without need of introducing into C++ language any of two limitations
presented above) will make proposed change cooperate well with existing
C++ features.</p>
<p>If proposed change with this is accepted, following code will be well formed:</p>
<blockquote>
	<pre>struct K
{
  int i;
  K(int i) : i (i) {}

  friend K&amp; operator=(K&amp; lh, const K&amp; rh)
  {
    lh.i = rh.i;
    return lh;
  }
};
</pre>
</blockquote>
<p>Sample code presented in above two sections (3.1 and 3.2) would be ill-formed,
because overloaded copy assignment in these samples is declared outside of function definition.
Author is in favour of allowing overloading of copy assignment as non-member
function with only this limitation (provided that problem described in section 4
is resolved), or allowing alternative solution described in section 4.1.</p>
<h3><a name="discussion"></a>4. Discussion</h3>
<p>Currently copy assignment operator declared in base class is always hidden by
copy assignment operator declared in derived classes (overloaded or declared implicitly by compiler). Author of this proposal is convinced that this is
important feature of the C++ language, and no changes in the C++ Standard should
harm it. However this proposal and N1582 might actually introduce changes that may affect this feature:</p>
<ol>
<li>&nbsp; if derived class is defined <tt>explicit</tt> (as proposed in
N1582), it does not have assignment operator implicitly declared by compiler.
If there's also no overloaded copy assignment, there's actually no declaration of copy
assignment that would hide the one declared in its base class. Following code
demonstrates the problem:
<blockquote>
	<pre>struct Base
{
  Base&amp; operator=(const Base&amp;);
};

explicit struct Derived : public Base // as proposed in N1582
{
  default Derived();
  default ~Derived();
};

int main()
{
  Derived d1;
  Derived d2;
  d1 = d2;          // Base::operator= is not hidden
}
</pre>
</blockquote>
</li>
<li>&nbsp; if copy assignment has been declared as non-member function of some
class and it's first parameter is reference to said class (as proposed
in this document), then value of class derived from given class may be bound
to such parameter. Because non-member function may not be hidden, such overloaded
copy assignment would always be present in set of available overloads and selected if it is best match. Under some scenarios such overloaded
non-member copy assignment operator will be best, or even only one, match. Following code demonstrates this problem:
<blockquote>
	<pre>struct Base
{
  friend Base&amp; operator=(Base &amp;lh, int);
  friend Base&amp; operator=(Base &amp;lh, const Base&amp;);
};

struct Derived : public Base
{
  Derived(void * = 0);
  Derived&amp; operator=(const Derived&amp;);
};

int main()
{
  Derived d;
  d = 1;       // operator=(Base &amp;lh, int) is best match
  d = Base();  // operator=(Base &amp;lh, const Base&amp;) is the only match
  d = 0;       // unexpected ambiguity
}
</pre>
</blockquote>
</li>
</ol>
<p>Resolution for both these problems is needed. Author does not have solution
for the first problem stated above. Second problem might be fixed if the C++ Standard
is supplemented with rule stating that <em>left
operand of the copy assignment operator is not bound to reference to its base
class.</em></p>
<h3><a name="alternatives"></a> 4.1 Alternative solution</h3>
<p>Author believes that instead of allowing another form of copy assignment operator,
it might be possible to introduce additional qualifier for member function declaration.
This qualifier would identify functions that may be called only on lvalue. Example
below:</p>
<blockquote>
	<pre>struct K
{
  int i;
  K(int i) : i (i) {}

  K&amp; operator=(const K&amp; rh) &amp;; // &quot;&amp;&quot; is member function qualifier here
};

int main()
{
  K() = 1;    // ill-formed
}
</pre>
</blockquote>
<p>Such solution will introduce new, useful feature into core C++ language. It would possibly not
conflict with some C++ features stated above, however it remains to be verified
if it would cooperate well
with other features of the C++ language.</p>
<h2><a id="_5._References" name="_5._References"></a> 5.  References</h2>
<p>[1] <u>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1582.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1582.pdf</a></u></p>
&nbsp;

</body>

</html>
