title: C++ how to emulate a function without implicit conversions?
body: <p>I'm trying to use a function template (or some other templatized construction) to emulate a function without implicit conversions applied to either the arguments or the return expression. What's the most robust way to do this?</p>
  
  <p>Ideally, I'm trying to come up with a way to do this that's easy to hide behind a template or a macro, has decent error messages, and doesn't impose a runtime penalty.</p>
  
  <p>This is intended as a metaprogramming exercise; I'm not going to be doing this in production code.</p>
  
  <p>The function below, <code>func1</code> takes two <code>longs</code> and adds them together, performing conversions as usual.</p>
  
  <pre><code>long func1(long a, long b) {
    return a + b;
  }
  </code></pre>
  
  <p>I'd like to define <code>func</code> in such a way that <code>a</code> and <code>b</code> can only be <code>long</code>s and check at compile time that the <code>return</code> expression really does have the indicated type without an implicit conversion being inserted.</p>
  
  <p>For the sake of concreteness, I've tried to do this a couple of ways so far, and here they are.</p>
  
  <p>One way of preventing conversions (for the arguments only) is to use a function template with a deleted implementation and a specialization for the combination of arguments.</p>
  
  <pre><code>template &lt;class L1, class L2&gt;
  long func2(L1 a, L2 b) = delete;
  
  template&lt;&gt;
  long func2(long a, long b) {
    return a + b;
  }
  </code></pre>
  
  <p>It's also possible to use <code>enable_if</code> to accomplish the same thing.</p>
  
  <pre><code>template &lt;class L1, class L2&gt;
  std::enable_if_t&lt;
    std::is_same&lt;L1, long&gt;::value &amp;&amp; std::is_same&lt;L2, long&gt;::value
  , long&gt; func3(L1 a, L2 b) {
    return a + b;
  }
  </code></pre>
  
  <p>However, I can't figure out how to incorporate an assertion about the return type without costing myself a copy or a move, or needing to do complex things to strip CV qualification and ref-ness. </p>
  
  <pre><code>// doesn't work, unnecessary copy
  template &lt;class L1, class L2&gt;
  std::enable_if_t&lt;
    std::is_same&lt;L1,long&gt;::value &amp;&amp; std::is_same&lt;L2,long&gt;::value,
  long&gt; func4(L1 a, L2 b) {
    auto out = a + b;
    static_assert(std::is_same&lt;decltype(out), long&gt;::value);
    return out;
  }
  </code></pre>
  
  <p>I can, however, move the function body into a lambda and then use <code>static_assert</code>s to list all the conditions I want. I'm a little concerned that this approach does something surprising.</p>
  
  <pre><code>template &lt;class L1, class L2&gt;
  long func5(L1 a, L2 b) {
    static auto wrapped = [&amp;](){
      return a + b;
    };
    static_assert(std::is_same&lt;decltype(a), long&gt;::value);
    static_assert(std::is_same&lt;decltype(b), long&gt;::value);
    static_assert(std::is_same&lt;decltype(wrapped()), long&gt;::value);
    return wrapped();
  }
  </code></pre>