<!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 (Revision 1)</title>
</head>

<body>

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td>N4170</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td>2014-08-12</td>
  </tr>
  <tr>
    <th>Project:&nbsp;&nbsp;</th><th> </th><td>Programming Language C++, Library Evolution Working Group</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </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 (Revision 1)</a></h1>

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

<p>This proposal extends the definition of <code><em>INVOKE</em></code> for class member pointers to cover types convertible to the 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="revision">Revision history</a></h2>

<p>Changes since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3719.html">N3719</a>:</p>
<ul>
  <li>Extended Motivation and Scope section.</li>
  <li>Added description of silent code change caused by previous
      resolution rules to Design Decisions.</li>
  <li>Changed wording to make resolution of ambiguity independent
      of the member function qualifiers.</li>
  <li>Removed Alternate Wording section. Linked to previous version
      instead.</li>
  <li>Incorporated fixes suggested by Andrzej Krzemieński.</li>
</ul>

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

<p>The definition of <code><em>INVOKE</em></code> in the Standard handles pointers to members
by defining two free standing functions: one that takes a reference and the other that takes 
a pointer (including smart pointers) to target class. 
However, there is a difference in semantics between the <code><em>INVOKE</em></code> expression
for pointers to members and functors: for pointers to members the conversions are not taken into
consideration when matching the first argument.</p>

<p>This difference in behaviour prohibits the uses of wrapper types (e.g., <code>std::reference_wrapper</code>,
<code>boost::flyweight</code>) in combination with pointers to members inside the Standard Library functions 
that are defined in terms of <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 by extending the definition of
<code><em>INVOKE</em></code> to allow implicit conversions in such situations.</p>

<p>The proposed change will also cover the cases like <code>std::chrono::duration</code> specializations,
where a family of types convertible to one common 'base' model the same logical entity.
With the acceptance of this proposal, expression 
<code>std::bind(&amp;std::chrono&lt;double&gt;::count, _1)</code> will create a functor returning the number of 
seconds for any specialization of std::chrono::duration.</p>

<p>In addition, this proposal allows the conversion to the target type to be applied
on the result of the dereference operator. This handles types similar to
<code>synchronized_value</code> proposed in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4033.html">N4033</a>.</p>

<h3><a name="motivation.workarounds">Existing workarounds</a></h3>

<h4><a name="motivation.workarounds.dereference-operator">Defining <code>operator*</code></a></h4>

<p>A well known 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 to an inelegant interface that combines wrapper and
pointer semantics.</p>

<h4><a name="motivation.workarounds.lambda">Using lambda</a></h4>

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

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

<p>In the case of <code>bind</code> expressions the problem may be mitigated by the 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 are defined in terms of <code><em>INVOKE</em></code> 
(e.g., <code>std::async</code>, <code>std::call_once</code>).</p>

<h3><a name="motivation.generic-aproach">Comparison with alternate solutions</a></h3>

<p><a href="http://isocpp.org/files/papers/n3522.html#2219">LWG issue #2219</a> proposes that <code><em>INVOKE</em></code> 
be specialized for class template <code>reference_wrapper</code>. Indeed, if we take a look at the examples above, we may
find that the only one, that is commonly used is <code>reference_wrapper</code>. This requires less changes to the
standardese.</p>

<p>The problem with this solution is that it is not taking into account the need to support user-defined types, both existing ones 
and ones developed in future. In contrast, the solution presented in this proposal is consistent with the design of the standard 
library which aims to provide equal support both for user-defined types and standard components, even at the cost of the increased 
complexity of the definition.
Most notable examples include:</p> 
<ul>
  <li>ranged based for loop supports any type of container that defines <code>begin</code>/<code>end</code> operations
      (both as member or free function found by argument depended lookup);</li>
  <li><code>condition_variable_any</code> is provided in addition to <code>condition_variable</code>, 
      to provide to support for any lock type;</li>
  <li><code><em>INVOKE</em></code> expression is supporting any deference type that returns reference to type compatible
      with member class.</li>
</ul>

<p>Furthermore, it has been suggested that if a user-defined type needs to work with <code><em>INVOKE</em></code>,
it can achieve the goal by defining <code>operator*</code>. If this were to be a valid advice, we would expect it
to also apply to <code>reference_wrapper</code>. However, in the case of <code>reference_wrapper</code> a special
dedicated solution is being proposed, which indicates that the original advice is insufficient; probably also for 
user-defined types.</p>

<p>In conclusion, the author perceives the addition of a single exception to the standard library in order to support
a single standard class, a non-feasible solution, both from the language learning perspective and the usability of the
language, especially in the context of designing library that should interoperate with standard ones.</p>

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

<h3><a name="design.amibiguity">Resolving ambiguity between dereference operator and conversion</a></h3>

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

<p>For 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>. The existence of such class in codebase might be the result of using a
<a href="#motivation.dereference-operator">work around</a> presented in the motivation section of this proposal.</p>

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

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

<p>Rising an error will make the behaviour of <code><em>INVOKE</em></code>
for member pointers more uniform with the behaviour of free standing 
functions. However, it will break existing code that uses such entities.</p>

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

<p>This is the only option that extends <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>

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

<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>

<h4><a name="design.amibiguity.summary">Summary</a></h4>

<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="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3719.html#alternate">Alternate proposal</a>
section of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3719.html">N3719</a>.
Third option is not further discussed.</p>

<h3><a name="design.preference-rules">Preference rules for dereference operator</a></h3>

<p>According to wording presented in the first version of this proposal dereference
operator was preferred over conversion if it's result type was compatible with 
cv-qualification and ref-qualification of member function pointer.
For example, given the following definitions:</p> 
<pre>
struct Clazz
{
  void foo();
};

struct Wrapper
{
  A const&amp; operator*();
  operator A&amp;();
};</pre>
<p>expression <code>std::mem_fn(&amp;A::foo)(Wrapper())</code> will use conversion operator 
because member function <code>foo</code> cannot be invoked on a const object.</p>

<p>As a consequence of the above behaviour, the modification of cv-qualification of the function may lead
to silent code changes. Let's imagine the situation in which member function <code>foo</code>
becomes const-qualified; such modification will silently change meaning of expression <code>std::mem_fn(&amp;A::foo)(Wrapper())</code>,
that will invoke dereference operator instead of conversion.
The author considers such change unacceptable because -- unlike in the case when we change one function overload for another --
we cannot reliably expect that dereference operator and conversion wiould have similar behaviour.</p>

<p>In order to avoid the described problem, the current revision of the paper includes new rules for selecting the dereference operator:
<i>the deference operator is selected if it returns a type that is implicitly convertible to a reference to target class of member pointer, however cv-qualified.</i></p>

<p>The proposed resolution keeps the above example ill-formed, preserving behaviour defined in the current standard.
In addition, it greatly simplifies usage of components defined in terms of <code><em>INVOKE</em></code>,
by making their behaviour for pointers to members independent of the actual nature of the member: data or function.</p> 

<p>Please also note that the wording change is only impacting cases of ambiguous wrappers that define both dereference operator
and conversion. Furthermore, the problem would not be present, if compilation error approach was selected as resolution in such situations.</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.9.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>Given the exposition only functor:</p>
<pre>
template&lt;typename T&gt;
struct to_reference
{
  T&amp; operator()(T&amp; t) const { return t; }
  T const&amp; operator()(T const&amp; t) const { return t; }
  T volatile&amp; operator()(T volatile&amp; t) const { return t; }
  T const volatile&amp; operator()(T const volatile&amp; t) const { return t; }

  T&amp;&amp; operator()(T&amp;&amp; t) const { return std::move(t); }
  T const&amp;&amp; operator()(T const&amp;&amp; t) const { return std::move(t); }
  T volatile&amp;&amp; operator()(T volatile&amp;&amp; t) const { return std::move(t); }
  T const volatile&amp;&amp; operator()(T const volatile&amp;&amp; t) const { return std::move(t); }
};
</pre></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>:
        <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>; otherwise</li>
          <li><code>(to_reference&lt;T&gt;{}(*t1).*f)(t2, ..., tN)</code> when <code>*t1</code> is implicitly convertible to a reference to an object of type <code>T</code>; otherwise</li>
          <li><code>(to_reference&lt;T&gt;{}(t1).*f)(t2, ..., tN)</code> when <code>t1</code> is implicitly convertible to a reference to an object of type <code>T</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>:
        <ul>
          <li>if <code>N != 1</code> expression is ill-formed; otherwise</li>
          <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>; otherwise</li>
          <li><code>to_reference&lt;T&gt;{}(*t1).*f</code> when <code>*t1</code> is implicitly convertible to a reference to an object of type <code>T</code>; otherwise</li>
          <li><code>to_reference&lt;T&gt;{}(t1).*f</code> when <code>t1</code> is implicitly convertible to a reference to an object of type <code>T</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="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, Andrzej Krzemieński 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#%21topic/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>Anthony Williams, "N4033: <code>synchronized_value&lt;T&gt;</code> for associating a mutex with a value" (N4033, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4033.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4033.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>
