
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