
Andrea Torsello <torsello@dsi.unive.it> writes:
David Abrahams wrote:
Oh, OK, if you assume that the compiler can always perform return value optimization, you are right. But I feel there is a difference in requiring the compiler to perform RVO on direct initialization from temporaries and requiring the compiler to perform it every time it is possible.
You appear to be making an argument about what's theoretically going to work in correct, portable C++, based on the behavior of a particular compiler implementation.
I am not requiring RVO unless you take what EDG accepts in strict mode as the defintion of "standards conforming". I do not. EDG is erroneous, IMO, in issuing that error, so we either turn off strict mode or work around it by allowing its native RVO to work. GCC has a much better example of what I consider a correct interpretation of the standard in requiring that it be possible to construct a new temporary rvalue from an existing one that will be bound to a reference (and not "copy construct", as I point out in N1610).
What I was saying is that if you provide a non-explicit X(X const &) constructor when passing a temporary by value you are performing a copy. So if you provide a non explicit copy ctor, you are requiring the compiler to perform RVO or you would have an extra copy. If you can assume the compiler can peform RVO in all cases why have the move construct at all?
Right. That said, for Intel C++ I am not providing any X(X const&) ctor, because it acts like comeau in non-strict mode (except that it doesn't warn either), and thus will optimize direct initializations when I am using the fancy move ctors.
But who would want to suppress RVOs in favor of move construction, anyway?
No-one, clearly. And Yes, all modern compilers support at least some RVO. I am just not sure whether this SOME is enough in all cases. I'd love to believe it is, but I am a bit scheptical.
My library is not relying on it being enough. It's just turning off the mechanisms needed for non-RVO'ing compilers where appropriate.
You still need to convert to temporary in initializer lists, since you cannot use the assigment constructor there, but most likely you would have to do it anyway.
Is that just speculation? I can't understand why you'd make that claim, since the CWG thinks that a prohibition on copying rvalues is possible.
I believe we are talking about two different things here. I was thinking about cases where you have a movable class with movable members.
class X : public movable<X> { ... };
class Y : public movable<y> { X x; public: Y(move_from<Y> y) : x(move_from<X>(y.x)) {} ^^^^^^^^^^^^^^^^^
clearly, "Y(move_from<Y> y) : x(y.x) {}" would not be able to move from x since in this context y.x is an lvalue.
That's what the explicit "move(x)" function is for: class Y : public movable<y> { X x; public: Y(move_from<Y> y) : x(move(y->x)) {}
Oh, right! There is probably no way around explicitly writing both constructors
I just got finished describing how it could be done using implicit_cast. Did you not understand that?
Sorry, didn't parse the last part correctly. You are right, if "const_lvalue" is convertible to T&, you can force the conversion in both initializer lists and still use a single macro. But it would still be the user's duty to explicitly force the conversion in initializer list, wouldn't it?
When required. Sometimes you can rely on the implicit conversion.
I am not sure wether it is easier on the user to have him force a conversion in a situation that he normally would not than just tell him that he needs two separate constructors, one for const and one non-const lvalues.
Considering that most/all of my ctors' logic is in the initializer list and that the two ctors' initializers will be different, I like having a way to make them the same.
but you can avoid duplication by putting the constructor's body in a private member function and forward from both constructors to it. At least that is what I have been doing.
If it were that easy you could do it with macros by inserting a surrounding brace pair and initializing a T const& there. Unfortunately, it doesn't handle the initializer list and I almost never have code in the ctor body.
Yes users would still have to provide the initializer lists.
Only one initializer list need be provided, using implicit_cast<> if neccessary.
Clearly delegating the construction is worth only if the constructor has a non-trivial body
Yep. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com