C++ Logo

sg10

Advanced search

Re: [SG10] A feature macro for mandatory copy elision

From: Richard Smith <richard_at_[hidden]>
Date: Fri, 6 Oct 2017 12:10:58 -0700
On 5 October 2017 at 21:15, Ville Voutilainen <ville.voutilainen_at_[hidden]>
wrote:

> On 6 October 2017 at 02:33, Richard Smith <richard_at_[hidden]> wrote:
> >> > I can't write
> >> > NoCopyNorMove x = factory();
> >> > in C++14. It's ill-formed. Same goes for
> >> > auto x = factory();
> >> >
> >> >
> >> > The macro does not help you with that. It does not magically make a
> >> > C++17
> >> > feature appear in C++14 mode.
> >>
> >> I can avoid compiling that when I know it won't work, for which I can
> >> use the macro. I can compile that when I know
> >> it'll work, for which the macro tells me that it'll work.
> >
> >
> > The thing I'm missing is what alternative you use when the feature is not
> > available, and why you would not use that alternative in all cases if you
> > want your code to be portable across compilers. Your original example is
> not
> > that, because you can just use the version with
> > __cpp_guaranteed_copy_elision not defined, with no loss of functionality.
>
> It's not about loss of functionality, necessary; the C++14 version has
> very different design trade-offs:
> 1) it can only ever be used with factories that are friends
>
2) it can only ever be used with factories when lifetime-extending
> references are used
>
A probable alternative is to decide that the type is not provided by
> the library at all if those trade-offs
> aren't palatable.
>
> >> > The choice is that rather than performing tricks with having to
> >> > befriend every possible factory function
> >> > and forcing users to use lifetime-extending references, such RAII
> >> > handles are provided only when copy
> >> > elision is available, and otherwise completely different tools need to
> >> > be
> >> > used.
> >> >
> >> >
> >> > I think we're still missing an example of that.
> >>
> >> That would be wrapping the whole type in #ifdef
> >> __cpp_mandatory_copy_elision, and providing
> >> a different type that doesn't rely on copy elision, like a type that
> >> is movable and has a different name.
> > This sounds promising. Can you give an example?
>
> I can provide two:
>
> #ifdef __cpp_mandatory_copy_elision
> class NoCopyNoMove {...};
> #else
> /* providing this type in C++14 mode is so icky that we simply don't */
>

Note that you've been able to do this since C++11:

class NoCopyNoMove {
public:
  NoCopyNoMove(const NoCopyNoMove&) = delete;
  NoCopyNoMove &operator=(const NoCopyNoMove&) = delete;

  NoCopyNoMove(int a, int b, int c);
};

NoCopyNoMove factory(int a) {
  // ...
  return {a, 2, 3}; // constructs return value in place
}

void use() {
  auto &&v = factory();
}

(If you happen to have mandatory copy elision then client code gets to use
"auto v = factory();" instead.)

After a while pondering, the best example I've got to demonstrate a need
for the feature test macro is something like this:

#ifdef __cpp_mandatory_copy_elision
NoCopyNoMove indirectFactory() {
  return factory(1); // ill-formed prior to C++17
}
#endif

#endif
>
> #ifdef __cpp_mandatory_copy_elision
> class NoCopyNoMove {...};
> #else
> class NoCopyNoMoveTransitional [[deprecated]] {...};
> #endif
>

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.

If copy elision is not available, chances are that there's no reason
> to encourage using the alternative
> type that has design downsides.
>
> Mandatory copy elision changes what code is valid and what is not. I
> find it odd that it's so hard to have a feature
> macro for something like that.


>

Received on 2017-10-06 21:11:22