title: Is it possible to intentionally defeat guaranteed copy elision for a particular type?
body: <p>In C++17 and above, <a href="https://stackoverflow.com/a/38043447/1505451">guaranteed copy elision</a> means that it's possible to return non-moveable objects frun a chain of functions, all the way to the ultimate caller:</p>
  <pre class="lang-cpp prettyprint-override"><code>struct NonMoveable {
    NonMoveable() = default;
    NonMoveable(NonMoveable&amp;&amp;) = delete;
  };
  
  NonMoveable Foo() { return NonMoveable(); }
  NonMoveable Bar() { return Foo(); }
  NonMoveable Baz() { return Bar(); }
  
  NonMoveable non_moveable = Baz();
  </code></pre>
  <p><strong>Is there some trick to <em>disable</em> guaranteed copy elision for a particular type</strong>, so that it's not possible to write functions like <code>Bar</code> and <code>Baz</code> above that pass through a <code>NonMoveable</code> object obtained from another function? (I'm agnostic as to whether <code>Foo</code> should be disallowed or not.)</p>
  <hr />
  <p>I know this is a weird request. If you're interested in what I'm trying to do: I'm working on a coroutines library, where the convention is that if you return a <code>Task</code> from a function then all of the reference parameters for that function need to remain valid until the task is ready, i.e. until a <code>co_await</code> expression for the task evaluates. This all totally works out fine if a coroutine is called from another coroutine, since I've arranged for the <code>Task</code> type to be non-moveable and accepted by value: you <a href="https://stackoverflow.com/a/72169170/1505451">can't do anything with it</a> except immediately <code>co_await</code> it, and any temporaries you provide in the call to the child coroutine will live until the <code>co_await</code> expression evaluates.</p>
  <p>Except you can do one more thing with <code>Task</code>: write functions like <code>Bar</code> and <code>Baz</code> above that do <code>return Foo()</code> instead of <code>co_return co_await Foo()</code>. If there is an argument to <code>Foo</code> involved it might be a temporary, in which case it's safe to <code>co_return co_await Foo(...)</code> but not <code>return Foo(...)</code>.</p>
  <p>This can get surprisingly subtle. For example a <code>std::function&lt;Task(SomeObj)&gt;</code> internally contains a <code>return</code> statement and will happily bind to a lambda that accepts <code>const SomeObj&amp;</code>. When it's called it will provide the lambda a reference to its by-value parameter, which is destroyed when the lambda suspends.</p>
  <p>I'm looking for a more elegant way to prevent this problem, but in the meantime I'd like to make the problematic form just not compile (which also helps identify the set of problems in user code). I expect this is not possible, but perhaps there is some trick I haven't thought of.</p>