A class must have a valid copy or move constructor for any of this syntax to be legal:
C x = factory();
C y( factory() );
C z{ factory() };
In
On your main question:
The question is, how to initialize a nonstatic member from a factory function returning non-copyable, non-moveable type?
You don't.
Your problem is that you are trying to conflate two things: how the return value is generated and how the return value is used at the call site. These two things don't connect to each other. Remember: the definition of a function cannot affect how it is used (in terms of language), since that definition is not necessarily available to the compiler. Therefore, C++ does not allow the way the return value was generated to affect anything (outside of elision, which is an optimization, not a language requirement).
To put it another way, this:
C c = {...};
Is different from this:
C c = [&]() -> C {return {...};}()
You have a function which returns a type by value. It is returning a prvalue expression of type C
. If you want to store this value, thus giving it a name, you have exactly two options:
Store it as a const&
or &&
. This will extend the lifetime of the temporary to the lifetime of the control block. You can't do that with member variables; it can only be done with automatic variables in functions.
Copy/move it into a value. You can do this with a member variable, but it obviously requires the type to be copyable or moveable.
These are the only options C++ makes available to you if you want to store a prvalue expression. So you can either make the type moveable or return a freshly allocated pointer to memory and store that instead of a value.
This limitation is a big part of the reason why moving was created in the first place: to be able to pass things by value and avoid expensive copies. The language couldn't be changed to force elision of return values. So instead, they reduced the cost in many cases.