Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-04-17 09:23:52


"Andrea Torsello" <torsello_at_[hidden]> writes:

> "David Abrahams" <dave_at_[hidden]> writes:
>>
>> By the way, if you are willing to give up on move semantics from
>> direct initialization, my technique will work in Comeau strict mode
>> just as well as yours. Nothing about what you did will get around
>> that problem; it seems to be a fact of current EDG compilers that in
>> strict mode direct initialization from an rvalue will only ever use an
>> ordinary (T const&) copy ctor.
>
> tested
> void sink(X const &);
> X source();
> void foo() { sink(source()); }
> on Comeau strict does not compile...
> everywhere else it does.

My point is that if you disable the library mechanisms that make
direct initialization move instead of copy from rvalues:

       X a(source()); // a case you're explicitly not handling

then the sink(source()) example compiles in strict mode. The default
setting of my library is now configured that way for comeau.

>> Please do. Also please use the latest version of the code in the
>> sandbox to test against.
>
> Last test was a couple of months ago when I was working activly on this,
> will do on most recent version I can find

IIRC I hadn't even posted my thing a couple of months ago(?)

> As I said on another message, my moving class was parametrized on
> templated type Tp and had a converting constructor and operator =
>
> template<class U> explicit X(X<U> const &);
>
> there is the solution
>
> template<class U> explicit X(X<U> const &,
> enable_if_different<U,Tp,char>::type=0);
>
> but adds extra requirements on unrelatd features. The same applies
> to the enable_if_same<T const, X const, void>::type return type for
> non temporary overloaded functions. It looks like my approach
> doesn't do anything your approach cannot do (not surprisingly since
> the only difference is in the technique I use to make X(X const &)
> less "priviledged" than the other constructors), but it appears to
> have less interactions with other language features. And hence less
> requirements on the library user.

Can you please show a succinct example of "less interactions" so that
I can do a comparison?

>> Actually I'm not sure what I was trying to say anymore. I can state
>> that my library already allows
>>
>> sink(source());
>>
>> to work transparently with move semantics on all compilers I've
>> tested on.
>
> as stated before if sink is "void sink(X const &);" Comeau in strict mode
> complains that there is no X(X const &) constructor.

As stated before, no it doesn't. Please test my code first and make
claims about it later.

>> Sorry, that wans just a mistake; it isn't convertible to anything. I
>> meant:
>>
>> template <class T> // lvalues
>> typename enable_if_same<T const, X const, void>::type f(T&);
>>
>> void f(move_from<X>); // temporaries
>
> Oh, OK that would work with operators as well, still with my approach it
> would be:
>
> void f(X&);
> void f(X::constant);
> void f(X::temporary);
>
> which, to me, seems easier from the user perspective. Clearly, this is just
> a matter of taste.

Not entirely. Your approach entails some code duplication between the
first two overloadsq. I guess the first f can be:

   void f(X& x) { X::constant(x); }

But then what happens when f takes two or three arguments, both of
which might be movable rvalues? I see an exponential explosion of
overloads coming.

>> It's no worse a problem than replacing what should be a reference
>> paramter with another type that can be constructed by implicit
>> conversion. You still cut off the possibility of user-defined
>> conversions.
>
> Yes. I was not claiming that forcing a templated function was an
> unsurmoutable problem, obviously there are ways aroud it. But think
> from the perspective of the user: even if you hide the details of
> the function definition with macro tricks, suddenly the user cannot
> keep the function on a separate compilation unit unless the macro
> manages to perform the explicit instantiation as well, which would
> be hard since you should explicitly instantiate two specializations:
> one for type X and one for type X const.

What macro tricks? I only use those for the copy ctor and assignment
operator because those may otherwise entail duplicating the function
body.

>> I don't see any advantages yet.
>
> Nothing your approach doesn't allow with some work (except Comeau
> not allowing to pass by const reference),

I'll ignore that one.

> but less interactions with orthogonal language features the user
> should know about.

I'm still interested in seeing how that happens.

> The only problem I have encountered so far comes from X x(makeX());
> calling the explicit copy constructor (X x=makeX(); does not).
> While in this case the approach fails to move, it is by far the
> easyest case for compiles to perform return value optimization.

I'm afraid not...

> The only compiler I have seen not performing the optimization is
> Comeau in strict mode.

...and hence, all the EDG-based compilers do the same thing unless
they're trying to emulate microsoft.

>> >> I still don't understand why you think it's important to
>> >> distinguish const temporaries from const lvalues.
>> >
>> > As you said in another post, it is not a problem to move from a const
>> > temporary (the compiler might just copy the const temporary to a non
>> > const temporary and optimize the copy away), hece you want to move
>> > from const temporaries.
>>
>> Which my library does.
>
> Never claimed it does not.

Sorry, you wrote:

  "I chose to keep the temporary and constant subtypes from mojo
  because they allow me to discriminate between const values,
  non-const rvalues and non-const rvalues. The lack of this
  capability was the major problem I had with David Abrahams' move."

I'm still trying to understand why it's a problem.

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk