<!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>A proposal to add invoke function template</title>
</head>

<body>

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;<th> <td>N3727</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;<th> <td>2013-08-01</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">A proposal to add invoke function template</a></h1>

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

<p>The aim of this proposal is to introduce the function template <code>invoke</code> that models <code><em>INVOKE</em></code> expression.</p>

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

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

<p>Although the behaviour of the <code><em>INVOKE</em></code> expression may be reproduced by combination of the existing standard library components, separate treatment of the functors and member pointers is required in such solutions.</p>

<h3><a name="motivation.deref-example"><code>deref_fn</code> example</a></h3>

<p>As example, please consider the <code>deref_fn</code> wrapper, that should accept any callable object <code>f</code> and return a functor that invokes provided callable and dereferences the result.</p>

<p>Using existing C++14 standard facilities <code>deref_fn</code> function may be implemented as:</p>
<pre>
  template&lt;typename F, std::enable_if_t&lt;!std::is_member_pointer&lt;std::decay_t&lt;F&gt;&gt;{}, int&gt; == 0&gt;
  auto deref_fn(F&amp;&amp; f) 
  { 
    return [f](auto&amp;&amp;... args) { return *f(std::forward&lt;decltype(args)&gt;(args)...); };
  } 

  template&lt;typename F, std::enable_if_t&lt;std::is_member_pointer&lt;std::decay_t&lt;F&gt;&gt;{}, int&gt; == 0&gt;
  auto deref_fn(F&amp;&amp; f)
  { 
    return [mf = std::mem_fn(f)](auto&amp;&amp;... args) { return *mf(std::forward&lt;decltype(args)&gt;(args)...); };
  }
</pre>

<p>Proposed <code>invoke</code> function allows simpler implementation, that does not resort to use of SFINAE function overloading:</p>
<pre>
  template&lt;typename F&gt;
  auto deref_fn(F&amp;&amp; f) 
  { 
    return [f](auto&amp;&amp;... args) { return *std::invoke(f, std::forward&lt;decltype(args)&gt;(args)...); };
  }
</pre>

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

<h3><a name="design.constexpr"><code>constexpr</code> implementation</a></h3>

<p>Although there is possibility to implement standard conforming <code>invoke</code> function template as a <code>constexpr</code> function, the proposed wording does not require such implementation.
The main reason is to left it consistent with existing standard function objects, that could have such definition, like <code>std::mem_fn</code>, <code>std::reference_wrapper</code> and operator wrappers. 
Furthermore imposing such requirement will block the implementation of <code>invoke</code> that refers to <code>std::mem_fn</code>.</p>

<p>This proposal assumes that <code>constexpr</code> addition to the <code>&lt;functional&gt;</code> header would be applied consistently by a separate proposal.</p>

<p>Both <code>constexpr</code> and standard library based implementation are presented in <a href="#implementability">Implementability</a> section of the proposal.</p>


<h3><a name="design.remove_invoke">Removal of <code><em>INVOKE</em></code> expression</a></h3>

<p>The wording of this proposal may also be specified by moving the requirements of the <code><em>INVOKE</em></code> expression to definition of the <code>invoke</code> function template and replacing all existing references to the <code><em>INVOKE</em></code> expression by corresponding <code>invoke</code> function invocation.</p>

<p>The approach described above is not used in this proposal, primarily to give implementation freedom to the standard library providers (e.g., whether <code>invoke</code> should be defined in terms of <code>mem_fn</code> or vice versa).
In addition such approach will require changes in existing implementations of standard function objects, without providing any real benefit from the library user perspective.</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>After the declaration of <code>binary_function</code> in the section 20.10 [function.objects]/2 (Header <code>&lt;functional&gt;</code> synopsis), add:

<blockquote class="stdins"> 
<pre>  // 20.10.3, <em>invoke</em>
  template &lt;class F, class... Args&gt; typename result_of&lt;F&amp;&amp;(Args&amp;&amp;...)&gt;::type invoke(F&amp;&amp; f, Args&amp;&amp;... args);
  template &lt;class R, class F, class... Args&gt; R invoke(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
 
</blockquote>

<p>After paragraph 20.10.2 Requirements [func.require], insert a new paragraph. (Chapter [refwrap] (Class template <code>reference_wrapper</code>) becomes 20.10.?)</p>
  
<blockquote class="stdins"> 
<h4><a name="invoke">20.10.3 Function template <code>invoke</code> <span style="float:right">[invoke]</span></a></h4>

<pre>  template &lt;class F, class... Args&gt;
    typename result_of&lt;F&amp;&amp;(Args&amp;&amp;...)&gt;::type invoke(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
  <dl class="attribute">
    <dt>Returns:</dt> <dd><p><code><em>INVOKE</em>(std::forward&lt;F&gt;(f), std::forward&lt;Args&gt;(args)...)</code> ([func.require] 20.10.2).</p> </dd>
  </dl>

<pre>  template &lt;class R, class F, class... Args&gt;
    R invoke(F&amp;&amp; f, Args&amp;&amp;... args);
</pre>
  <dl class="attribute">
    <dt>Returns:</dt> <dd><p><code><em>INVOKE</em>(std::forward&lt;F&gt;(f), std::forward&lt;Args&gt;(args)..., R)</code> ([func.require] 20.10.2).</p> </dd>
  </dl>
 
</blockquote>

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

<p>Proposed <code>invoke</code> function template may be implemented in terms of existing C++11 standard library components:</p>
<pre>
  template&lt;typename Functor, typename... Args&gt;
  typename std::enable_if&lt;
    std::is_member_pointer&lt;typename std::decay&lt;Functor&gt;::type&gt;::value,
    typename std::result_of&lt;Functor&amp;&amp;(Args&amp;&amp;...)&gt;::type
  &gt;::type invoke(Functor&amp;&amp; f, Args&amp;&amp;... args)
  { 
    return std::mem_fn(f)(std::forward&lt;Args&gt;(args)...); 
  }
   
  template&lt;typename Functor, typename... Args&gt;
  typename std::enable_if&lt;
    !std::is_member_pointer&lt;typename std::decay&lt;Functor&gt;::type&gt;::value,
    typename std::result_of&lt;Functor&amp;&amp;(Args&amp;&amp;...)&gt;::type
  &gt;::type invoke(Functor&amp;&amp; f, Args&amp;&amp;... args)
  { 
    return std::forward&lt;Functor&gt;(f)(std::forward&lt;Args&gt;(args)...); 
  }

  template&lt;typename Return, typename Functor, typename... Args&gt;
  Return invoke(Functor&amp;&amp; f, Args&amp;&amp;... args)
  {
    return invoke(std::forward&lt;Functor&gt;(f), std::forward&lt;Args&gt;(args)...);
  }
</pre>

<p>An <code>constexpr</code> implemenatation may be found at: <a href="https://github.com/tomaszkam/proposals/blob/master/invoke/invoke_cpp11.hpp">https://github.com/tomaszkam/proposals/blob/master/invoke/invoke_cpp11.hpp</a>.</p>

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

<p>Joe Gottman originally proposed <code>invoke</code> function in discussion group <a href="https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-proposals/InJClAiLXcI">ISO C++ Standard - Future Proposals</a>.</p>
<p>Andrzej Krzemieński offered many useful suggestions and corrections to the proposal.</p>

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

<ol>

<li>Tomasz Kamiński, Implementation of invoke function (<a href="https://github.com/tomaszkam/proposals/blob/master/invoke/invoke_cpp11.hpp">https://github.com/tomaszkam/proposals/blob/master/invoke/invoke_cpp11.hpp</a>)</li>

</ol>

</body></html>
