<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>

  <meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">

<!-- This should replace the style block once it is published somewhere accessible
  <link href="../../base_www/style.hinc" rel="stylesheet" type="text/css" />
-->

  <style type="text/css">

    body { color: #000000; background-color: #FFFFFF; }
    del { text-decoration: line-through; color: #8B0040; }
    ins { text-decoration: underline; color: #005100; }

    p.example { margin-left: 2em; }
    pre.example { margin-left: 2em; }
    div.example { margin-left: 2em; }

    code.extract { background-color: #F5F6A2; }
    pre.extract { margin-left: 2em; background-color: #F5F6A2;
      border: 1px solid #E1E28E; }

    p.function { }
    .attribute { margin-left: 2em; }
    .attribute dt { float: left; font-style: italic;
      padding-right: 1ex; }
    .attribute dd { margin-left: 0em; }

    blockquote.std { color: #000000; background-color: #F1F1F1;
      border: 1px solid #D1D1D1;
      padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;
      color: #000000; background-color: #FFEBFF;
      border: 1px solid #ECD7EC;
      padding-left: 0.5empadding-right: 0.5em; ; }

    blockquote.stdins { text-decoration: underline;
      color: #000000; background-color: #C8FFC8;
      border: 1px solid #B3EBB3; padding: 0.5em; }

    table { border: 1px solid black; border-spacing: 0px;
      margin-left: auto; margin-right: auto; }
    th { text-align: left; vertical-align: top;
      padding-left: 0.8em; border: none; }
    td { text-align: left; vertical-align: top;
      padding-left: 0.8em; border: none; }

    table.docinfo { border: none; border-spacing: 0px;
      margin-left: auto; margin-right: none; float: right; }

  </style>

  <title>auto operator= considered dangerous</title>

</head>

<body>
  <table border="1" class="docinfo">
    <tr> <th>Doc. No.:</th> <td>P0264R0</td> </tr>
    <tr> <th>Date:</th>     <td>2016-02-11</td> </tr>
    <tr> <th>Project:</th>  <td>Programming Language C++</td> </tr>
    <tr> <th>Audience:</th> <td>Evolution Working Group</td> </tr>
    <tr> <th>Reply To:</th> <td>Michael Price<br/>
                                &lt;<a href="mailto:michael.b.price.dev@gmail.com">michael.b.price.dev@gmail.com</a>&gt;</td> </tr>
  </table>

  <br/>
  <h1><code>auto operator=</code> considered dangerous</h1>

  <h2><a name="introduction">I. Introduction</a></h2>

  <p>
    ISO/IEC 14882:2014 (C++14) introduced the ability to deduce the return type of a
    function by its definition body. N4309 proposed to extend this further by allowing
    return type deduction of certain special class member functions that are defined as
    <code>=default</code>. Discussion in EWG was somewhat favorable until the
    realization that <code>auto</code> <strong>never</strong> deduces a reference
    type, which is the overwhelmingly usual return type for those functions. This
    paper explores the problem area and offers a small set of alternatives to consider.
  </p>

  <h2><a name="motivation">II. Motivation</a></h2>

  <p>
    Paragraph 7.1.6.4, clause 2 of the standard states:
  </p>

  <blockquote class="std"><p>
    The placeholder type can appear with a function declarator in the
    <em>decl-specifier-seq</em>, <em>type-specifier-seq</em>,
    <em>conversion-function-id</em>, or <em>trailing-return-type</em>, in any
    context where such a declarator is valid. If the function declarator
    includes a <em>trailing-return-type</em> (8.3.5), that specifies the
    declared return type of the function. If the declared return type of the
    function contains a placeholder type, the return type of the function is
    deduced from <code>return</code> statements in the body of the function,
    if any.
  </p></blockquote>

  <p>
    This wording allows the usage of <code>auto</code> or <code>declspec(auto)</code>
    in a function definition, only if there is a trailing return type or a
    function body that contains at least one <code>return</code>
    statement that can be used to deduce the return type.
  </p>

  <pre class="example">
  struct ProbablyWrong
  {
      ProbablyWrong() = default;
      ~ProbablyWrong() = default;
      ProbablyWrong(const ProbablyWrong&amp;) { /* ... */ }
      ProbablyWrong(ProbablyWrong&amp;&amp;) = default;
      auto operator=(const ProbablyWrong&amp;) { /* ... */ return *this; }
      auto operator=(ProbablyWrong&amp;&amp;) { /* ... */ return *this; }
  };</code>
  </pre>

  <p>
    In the above example, the naive "<code>auto</code> everywhere" enthusiast
    has created a type where both the copy-assignment operator and the 
    move-assignment operator return a copy, instead of the usually desired
    action of returning <code>*this</code> by reference.
  </p>

  <h2><a name="alternatives">III. Alternative Implementations</a></h2>

  <p>
    There are many different forms that the return type deduction for these
    functions might reasonably take. Let's explore them. [Note: For
    brevity's sake, only one method is defined per alternative.]
  </p>

  <pre class="example">
  struct CorrectOne
  {
      auto&amp; operator=(CorrectOne&amp;&amp;) { /* ... */ return *this; }
  };

  struct CorrectTwo
  {
      decltype(*this) operator=(CorrectTwo&amp;&amp;) { /* ... */ return *this; }
  };

  struct CorrectThree
  {
      decltype(auto) operator=(CorrectThree&amp;&amp;) { /* ... */ return *this; }
  };

  struct CorrectFour
  {
      decltype(auto) operator=(CorrectFour&amp;&amp;) { /* ... */ return *this; }
  };

  struct CorrectButRisky
  {
      decltype(auto) operator=(Correct&amp;&amp; o) { return swap(o); }

      /* POSSIBLY LOTS AND LOTS OF LINES OF CODE */

      decltype(auto) swap(Correct&amp;&amp;) { /* ... */ return *this; }
  };</code>
  </pre>

  <p>
    Most of the variations of return type deduction will do the right thing, but
    the most "obvious" variation will most likely do something unexpected. Then
    we have the variation that delegates the return type deduction to an entirely
    different function. An unsuspecting maintainer could modify the <code>swap</code>
    function without realizing that it will modify the return type of a very
    important function 100s of lines away.
  </p>
 

  <h2><a name="what">IV. What Should We Do? </a></h2>

  <p>
    The committee has several (possibly non-exclusive) options available:
  <p>

  <ul>
    <li>Exempt special member functions from return type deduction entirely</li>
    <li>Draft special return type deduction rules for special member functions</li>
    <li>Encourage implementations and/or tool vendors to detect such errors</li>
    <li>Do nothing</li>
  </ul>

  <h2><a name="acknowledgements">V. Acknowledgements</a></h2>

  <p>
    The author would like to thank current and former employers who have supported
    their work with the committee, Synopsys and Lexmark, respectively. In
    particular, the keen eyes of EWG members who spotted this bad pattern should
    be thanked for their diligence.
  </p>

</body>
</html>
