<!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=UTF-8">

<style type="text/css">
pre {margin-left:20pt; }
pre > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
pre > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
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.header { border: 0px; border-spacing: 0;
  margin-left: 0px; font-style: normal; }

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

<title>Extend INVOKE to support types convertible to target class</title>
</head>

<body>

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;<th> <td>N3719</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;<th> <td>2013-08-17</td>
  </tr>
  <tr>
    <th>Project:&nbsp;&nbsp;<th> <td>Programming Language C++, Library Working Group</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;<th> <td><address>Tomasz Kamiński &lt;tomaszkam at gmail dot com&gt;</address></td>
  </tr>
</tbody></table>

<h1><a name="title">Extend INVOKE to support types convertible to target class</a></h1>

<h2><a name="intro">Introduction</a></h2>

<p>This proposal is to extend the definition of <code><em>INVOKE</em></code> for class member pointers to cover types convertible to a target class of the pointer, like <code>std::reference_wrapper</code>.</p>

<p>Proposal also resolves <a href="http://isocpp.org/files/papers/n3522.html#2219">LWG issue #2219</a></p>

<!--h2><a name="toc">Table of contents</a></h2-->

<h2><a name="motivation">Motivation and Scope</a></h2>

<p>The standard <code><em>INVOKE</em></code> expression models the member pointers as pair of free standing functions, that takes a reference and the pointer (including smart pointers) to target class respectively. However there is difference in semantics between the <code><em>INVOKE</em></code> expression for member pointers and functors - for member pointers the conversions are not taken into consideration in matching of first argument.</p>

<p>This behavior difference prohibit uses wrapper types (e.g., <code>std::reference_wrapper</code>, <code>boost::flyweight</code>) in combination with member pointers with the standard library functions that are modeled using <code><em>INVOKE</em></code> (e.g., <code>std::bind</code>, <code>std::mem_fn</code>, <code>std::async</code>). The aim of this proposal is to fix that usability problem via extending definition of <code><em>INVOKE</em></code> to allow implicit conversions in such situations.</p>

<p>Proposed change will also cover cases of set of convertible types that models the same logical entity (e.g., std::chrono::duration specializations). With the acceptance of this proposal, the <code>std::bind(&amp;std::chrono&lt;double&gt;::count, _1)</code> will create functor returning amount of seconds for any specialization of std::chrono::duration.</p>

<h3><a name="motivation.deference-operator">Defining <code>operator*</code></a></h3>

<p>The well know workaround for this problem, is to define the <code>operator*</code> that will return the same result as the conversion operator. Firstly this solution is only applicable in situations when the definition of the class can be changed, so it is not feasible for third-party library classes. Secondly it leads inelegant interface than combines wrapper and pointer semantics.</p>

<h3><a name="motivation.lambda">Using lambda</a></h3>

<p>The other workaround is to use the lambda expression instead of library functions, but in the most cases it leads to the less readable code. Please compare following code snippets:</p>
<pre>
  std::bind(&amp;foo, _1, expr, ref(a));
  [e = expr, &amp;a] (auto&amp;&amp; arg) -> decltype(auto) { return foo(std::forward&lt;decltype(arg)&gt;(arg), e, a); }
</pre>

<h3><a name="motivation.bind-cast">Define special cast functor</a></h3>

<p>In case of <code>bind</code> expressions the problem may be mitigated by introduction of additional cast functor that preforms required casting.</p>
<pre>
std::bind(&amp;Class::method, _1)(std::ref(clazz));
std::bind(&amp;Class::method, cast&lt;Class&amp;&gt;(_1))(std::ref(clazz));
</pre>
<p>However this solution depends on <code>std::is_bind_expression</code> trait and cannot be applied to other library components that depends of <code><em>INVOKE</em></code> (e.g., <code>std::async</code>, <code>std::call_once</code>).</p>

<h2><a name="design">Design Decisions</a></h2>

<p>Allowing conversion in <code><em>INVOKE</em></code> with member pointer may lead to ambiguity in case of entity <code>t</code>, for which both result of <code>t</code> and <code>*t</code> is implicitly convertible to target class of the pointer.</p>

<p>As example, for the following class:</p>
<pre>
  struct Clazz { int foo; }

  struct Mixed
  {
    Clazz&amp; operator*();
    operator Clazz&amp;();
  };
  
  Mixed m;
</pre>
<p>The expression <code><em>INVOKE</em>(&amp;Clazz::foo, m)</code> may be interpreted as <code>static_cast&lt;Clazz&gt;(m).*foo</code> or <code>static_cast&lt;Clazz&gt;(*m).*foo</code>. Existence of such in codebase class may be a result of using <a href="#motivation.deference-operator">work around</a> presented in the motivation section of this proposal.</p>

<p>There are tree possible behaviors in case of such ambiguity:</p>
  <ol>
    <li>Compilation error</li>
    <li>Preference of <code>operator*</code></li>
    <li>Preference of conversion</li>
  </ol>

<h3><a name="design.error">1. Compilation error</a></h3>

<p>Raising and ambiguity error will make behaviour of <code><em>INVOKE</em></code> for member pointers more uniform with behaviour of free standing functions. However it will break existing code, that uses entities that are both convertible to and behaves as a pointer to target class.</p>

<h3><a name="design.prefer-dereference">2. Preference of <code>operator*</code></a></h3>

<p>This is the only option that allow extensions of <code><em>INVOKE</em></code> definition without breaking or introducing silent behaviour changes in the existing code. The minor drawback is that it leads to more complicated definition of <code><em>INVOKE</em></code>.</p>

<h3><a name="design.prefer-conversion">3. Preference of conversion</a></h3>

<p>Preference of the conversion leads to the silent behaviour change of the existing C++11 standard compliant code, so this option should not be considered as a feasible solution.</p>

<h3><a name="design.summary">Summary</a></h3>

<p>This proposal recommends implementing the second option and provides the wording in the <a href="#wording">Proposed wording</a> section. The wording for the first option may be found in the <a href="#alternate">Alternate proposal</a> section. Third option is not further discussed.</p>

<h2><a name="standard">Impact On The Standard</a></h2>

<p>This proposal has no dependencies beyond a C++11 compiler and Standard Library implementation. (It depends on perfect forwarding, varidatic templates, <code>decltype</code> and trailing return types.)</p>

<p>Nothing depends on this proposal.</p>

<h2><a name="wording">Proposed wording</a></h2>

<p>Change the paragraph 20.10.2 Requirements [func.require].</p>

<blockquote class="stddel">
  <dl class="attribute">
     
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li><code>(t1.*f)(t2, ..., tN)</code> when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
      <li><code>((*t1).*f)(t2, ..., tN)</code> when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>t1</code> is not one of the types described in the previous item;</li>
      <li><code>t1.*f</code> when <code>N == 1</code> and <code>f</code> is a pointer to member data of a class <code>T</code> and <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
      <li><code>(*t1).*f</code> when <code>N == 1</code> and <code>f</code> is a pointer to member data of a class <code>T</code> and <code>t1</code> is not one of the types described in the previous item;</li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>
  
<blockquote class="stdins">
  <dl class="attribute">
     
    <dd><p>Define <em>viable reference types</em> for member pointer <code>p</code> of type <code>M T::*</code> as:
    </p><ul>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</code> for all possible cv-qualifiers <code><em>cv</em></code> if <code>M</code> is not function type,</li>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</code> if <code>M</code> is function type without ref-qualifier and with cv-qualifiers <code><em>cv</em></code>,</li>
      <li><code>T <em>cv</em> <em>ref</em></code> if <code>M</code> is function type with ref-qualifier <code><em>ref</em></code> and cv-qualifiers <code><em>cv</em></code>.</li>
    </ul><p></p></dd>

    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>TR</code> is <em>viable reference type</em> for <code>f</code>:
        <ul>
          <li><code>(t1.*f)(t2, ..., tN)</code> when <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
          <li><code>(TR{*t1}.*f)(t2, ..., tN)</code> when <code>t1</code> does not fulfill criteria of any of previous point and <code>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>(TR{t1}.*f)(t2, ..., tN)</code> when <code>t1</code> does not fulfill criteria of any of previous point and <code>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>T</code> and <code>N == 1</code> and <code>TR</code> is <em>viable reference type</em> for <code>f</code>:
        <ul>
          <li><code>t1.*f</code> when <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
          <li><code>TR{*t1}.*f</code> when <code>t1</code> does not fulfill criteria of any of previous point and <code>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>TR{t1}.*f</code> when <code>t1</code> does not fulfill criteria of any of previous point and <code>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>otherwise expression is ill-formed;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name="alternate">Alternate proposal</a></h2>

<p>Change the paragraph 20.10.2 Requirements [func.require].</p>

<blockquote class="stddel">
  <dl class="attribute">
     
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li><code>(t1.*f)(t2, ..., tN)</code> when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
      <li><code>((*t1).*f)(t2, ..., tN)</code> when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>t1</code> is not one of the types described in the previous item;</li>
      <li><code>t1.*f</code> when <code>N == 1</code> and <code>f</code> is a pointer to member data of a class <code>T</code> and <code>t1</code> is an object of type <code>T</code> or a reference to an object of type <code>T</code> or a reference to an object of a type derived from <code>T</code>;</li>
      <li><code>(*t1).*f</code> when <code>N == 1</code> and <code>f</code> is a pointer to member data of a class <code>T</code> and <code>t1</code> is not one of the types described in the previous item;</li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>
  
<blockquote class="stdins">
  <dl class="attribute">
 
    <dd><p>Define <em>viable reference types</em> for member pointer <code>p</code> of type <code>M T::*</code> as:
    </p><ul>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</code> for all possible cv-qualifiers <code><em>cv</em></code> if <code>M</code> is not function type,</li>
      <li><code>T <em>cv</em>&amp;</code>, <code>T <em>cv</em>&amp;&amp;</code> if <code>M</code> is function type without ref-qualifier and with cv-qualifiers <code><em>cv</em></code>,</li>
      <li><code>T <em>cv</em> <em>ref</em></code> if <code>M</code> is function type with ref-qualifier <code><em>ref</em></code> and cv-qualifiers <code><em>cv</em></code>.</li>
    </ul><p></p></dd>
   
    <dd><p>Define <code><em>INVOKE</em>(f, t1, t2, ..., tN)</code> as follows:
    </p><ul>
      <li>when <code>f</code> is a pointer to a member function of a class <code>T</code> and <code>TR</code> is <em>viable reference type</em> for <code>f</code>:
        <ul>
          <li><code>(TR{t1}.*f)(t2, ..., tN)</code> when <code>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>(TR{*t1}.*f)(t2, ..., tN)</code> when <code>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above points applies;</li>
        </ul>
      </li>
      <li>when <code>f</code> is a pointer to member data of a class <code>T</code> and <code>N == 1</code> and <code>TR</code> is <em>viable reference type</em> for <code>f</code>:
        <ul>
          <li><code>TR{t1}.*f</code> when <code>t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li><code>TR{*t1}.*f</code> when <code>*t1</code> is implicitly convertible to <code>TR</code>;</li>
          <li>the expression is ill-formed when neither or both of above points applies;</li>
        </ul>
      </li>
      <li><code>f(t1, t2, ..., tN)</code> in all other cases.</li>
    </ul><p></p></dd>

  </dl>
</blockquote>

<h2><a name='implementability'>Implementability</a></h2>

<p>Proposed change can be implemented as pure library extension in C++11. Implementation of <code>invoke</code> function that conforms proposed wording can be found <a href="https://github.com/tomaszkam/proposals/tree/master/invoke">https://github.com/tomaszkam/proposals/tree/master/invoke</a>.</p>

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

<p>Tomasz Miąsko and Mikhail Semenov offered many useful suggestions and corrections to the proposal.</p>
<p>Ville Voutilainen, Gabriel Dos Reis and other people in discussion group <a href="https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-proposals/FtilAt9V_1c">ISO C++ Standard - Future Proposals</a> provided numerous insightful suggestions.</p>

<h2><a name="literature">References</a></h2>

<ol>

<li>Alisdair Meredith, "C++ Standard Library Active Issues List (Revision R82)" (N3522, <a href="http://isocpp.org/files/papers/n3522.html">http://isocpp.org/files/papers/n3522.html</a>)</li>
<li>Tomasz Kamiński, Implementation of invoke function (<a href="https://github.com/tomaszkam/proposals/tree/master/invoke">https://github.com/tomaszkam/proposals/tree/master/invoke</a>)</li>

</ol>

</body></html>
