Boost logo

Boost :

Subject: Re: [boost] VC10 config - some regressions in several libraries
From: Jeffrey Hellrung (jhellrung_at_[hidden])
Date: 2010-04-29 14:00:47


Ion Gaztañaga wrote:
> On 26/04/2010 21:19, Stephan T. Lavavej wrote:
>> Writing code that works under rvalue references v1 and v2
>> simultaneously is generally easy. In particular, the move semantics
>> and perfect forwarding idioms are unaffected. However, extreme
>> caution must be used when reimplementing std::move() and
>> std::forward().
>
> I general I found both approaches similar but I can't port the following
> to v2. For "emplace" functions, is more efficient in terms of code size,
> to catch all references and pack them in a polymorphic class and so that
> the same binary code could be used for value all non value-constructing
> code. I imagine there are similar use cases for std::function or bind,
> where we want to catch all input parameters by reference and use them
> later.
>
> This was possible with v1 just storing some "T &&member_x" members in a
> class using forward (at least in gcc 4.3). However, I can't achieve this
> with VC 10 (I haven't tested gcc 4.5), because the compiler complains
> (it's surely right) about warning C4413. Here's the code (a simplified
> "emplace" function):
>
> //store_and_forward_func takes a Target type, catches all references,
> //packs them in store_and_forward class, and calls a deferred call
> //using the stored arguments:
>
> class int_holder
> {
> int _i;
> public:
> int_holder(const int &i)
> { _i = i; }
>
> int_holder(int &&i)
> { _i = i; i = 0;}
>
> void func(){}
> };
>
>
> template<class Target, class Arg>
> struct store_and_forward
> {
> Arg &&ref; //Stores a reference for further forwarding
> store_and_forward(Arg &&r)
> //warning C4413: reference member is initialized to a temporary
> //that doesn't persist after the constructor exits
> : ref(static_cast<Arg&&>(r))
> {
> //No warning with the same cast!
> //Correct binding
> Arg&& a = static_cast<Arg&&>(r);
> }
>
> void call()
> {
> Target a(static_cast<Arg&&>(ref));
> a.func();
> }
> };
>
>
> template<class Target, class Arg>
> void store_and_forward_func(Arg &&r)
> {
> struct store_and_forward<int_holder, Arg> fwd(static_cast<Arg&&>(r));
> fwd.call();
> }
>
> int main ()
> {
> //This should lead to a compilation error
> const int & cref = 1;
> //Ok
> store_and_forward_func<int_holder>(cref);
> //Bad forwarding, member reference is not bound
> //to the temporary int(6)
> store_and_forward_func<int_holder>(int(6));
> return 0;
> }
>
> A very similar code was possible with v1, but I can't get it work for v2.
>
> Best,
>
> Ion

I'm confused. So static_cast< Arg&& >(r) creates a new temporary object
(rather than just a (rvalue) reference to the r object) when used in
direct construction, but does not behave this way otherwise (e.g., the
line after "//Correct binding" above?

Somewhat unrelated to the above confusion, would a possible workaround
be to store the references just as lvalue references (and using the type
information to forward them as rvalue references)? I.e., does

...
     Arg& ref; // lvalue reference whether Arg is an object or rvalue
reference or lvalue reference type
     store_and_forward(Arg&& r) // Arg&& is an rvalue reference if Arg
is an object or rvalue reference type, lvalue reference if Arg is an
lvalue reference type
         : ref(r)
     { }
...

work? The expression "r" is, in fact, an lvalue reference to the actual
object, regardless of its declared type in the constructor parameter
list, right?

Maybe I don't know rvalue references as well as I had thought... :/

- Jeff


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