<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 5 October 2017 at 21:15, Ville Voutilainen <span dir="ltr"><<a href="mailto:ville.voutilainen@gmail.com" target="_blank">ville.voutilainen@gmail.com</a>></span> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">On 6 October 2017 at 02:33, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
>> > I can't write<br>
>> > NoCopyNorMove x = factory();<br>
>> > in C++14. It's ill-formed. Same goes for<br>
>> > auto x = factory();<br>
>> ><br>
>> ><br>
>> > The macro does not help you with that. It does not magically make a<br>
>> > C++17<br>
>> > feature appear in C++14 mode.<br>
>><br>
>> I can avoid compiling that when I know it won't work, for which I can<br>
>> use the macro. I can compile that when I know<br>
>> it'll work, for which the macro tells me that it'll work.<br>
><br>
><br>
> The thing I'm missing is what alternative you use when the feature is not<br>
> available, and why you would not use that alternative in all cases if you<br>
> want your code to be portable across compilers. Your original example is not<br>
> that, because you can just use the version with<br>
> __cpp_guaranteed_copy_elision not defined, with no loss of functionality.<br>
<br>
</span>It's not about loss of functionality, necessary; the C++14 version has<br>
very different design trade-offs:<br>
1) it can only ever be used with factories that are friends<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">2) it can only ever be used with factories when lifetime-extending<br>
references are used<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">A probable alternative is to decide that the type is not provided by<br>
the library at all if those trade-offs<br>
aren't palatable.<br>
<span class="gmail-"><br>
>> > The choice is that rather than performing tricks with having to<br>
>> > befriend every possible factory function<br>
>> > and forcing users to use lifetime-extending references, such RAII<br>
>> > handles are provided only when copy<br>
>> > elision is available, and otherwise completely different tools need to<br>
>> > be<br>
>> > used.<br>
>> ><br>
>> ><br>
>> > I think we're still missing an example of that.<br>
>><br>
>> That would be wrapping the whole type in #ifdef<br>
>> __cpp_mandatory_copy_elision, and providing<br>
>> a different type that doesn't rely on copy elision, like a type that<br>
>> is movable and has a different name.<br>
> This sounds promising. Can you give an example?<br>
<br>
</span>I can provide two:<br>
<br>
#ifdef __cpp_mandatory_copy_elision<br>
class NoCopyNoMove {...};<br>
#else<br>
/* providing this type in C++14 mode is so icky that we simply don't */<br></blockquote><div><br></div><div>Note that you've been able to do this since C++11:</div><div><br></div><div>class NoCopyNoMove {</div><div>public:</div><div> NoCopyNoMove(const NoCopyNoMove&) = delete;</div><div> NoCopyNoMove &operator=(const NoCopyNoMove&) = delete;</div><div><br></div><div> NoCopyNoMove(int a, int b, int c);</div><div>};</div><div><br></div><div>NoCopyNoMove factory(int a) {</div><div> // ...</div><div> return {a, 2, 3}; // constructs return value in place</div><div>}</div><div><br></div><div>void use() {</div><div> auto &&v = factory();</div><div>}</div><div><br></div><div>(If you happen to have mandatory copy elision then client code gets to use "auto v = factory();" instead.)</div><div><br></div><div>After a while pondering, the best example I've got to demonstrate a need for the feature test macro is something like this:</div><div><br></div><div>#ifdef __cpp_mandatory_copy_elision<br></div><div>NoCopyNoMove indirectFactory() {</div><div> return factory(1); // ill-formed prior to C++17</div><div>}</div><div>#endif</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
#endif<br>
<br>
#ifdef __cpp_mandatory_copy_elision<br>
class NoCopyNoMove {...};<br>
#else<br>
class NoCopyNoMoveTransitional [[deprecated]] {...};<br>
#endif<br></blockquote><div><br></div><div>If you do this, your customers' code breaks when they upgrade their compilers. I would hope/imagine you would instead provide the ...Transitional class unconditionally. That would then make this the same as the previous example.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
If copy elision is not available, chances are that there's no reason<br>
to encourage using the alternative<br>
type that has design downsides.<br>
<br>
Mandatory copy elision changes what code is valid and what is not. I<br>
find it odd that it's so hard to have a feature<br>
macro for something like that. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br></blockquote></div></div></div>