Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perfectly capturing a perfect forwarder (universal reference) in a lambda

So I have a perfect forwarder, and I want to appropriately capture it in a lambda, such that R-values are copied in, and L-values are captured by reference. However simply using std::forward doesn't do the job, as evidenced by this code:

#include<iostream>

class testClass
{
public:
   testClass() = default;
   testClass( const testClass & other ) { std::cout << "COPY C" << std::endl; }
   testClass & operator=(const testClass & other ) { std::cout << "COPY A" << std::endl; }
};

template< class T>
void testFunc(T && t)
   { [test = std::forward<T>(t)](){}(); }

int main()
{
   testClass x;
   std::cout << "PLEASE NO COPY" << std::endl;
   testFunc(x);
   std::cout << "DONE" << std::endl;

   std::cout << "COPY HERE" << std::endl;
   testFunc(testClass());
   std::cout << "DONE" << std::endl;
}

Compiling this with

g++ -std=c++14 main.cpp

Produces the output

PLEASE NO COPY
COPY C
DONE
COPY HERE
COPY C
DONE

In a perfect world, I would like to only have the "COPY C" appear in the rvalue case, not the lvalue case.

My work around would be to use a helper function overloaded for L- and R- values, but I was wondering if there was a better way.

Cheers!

like image 238
Hounddog Avatar asked Jul 14 '15 14:07

Hounddog


1 Answers

You may use the following:

[test = std::conditional_t<
             std::is_lvalue_reference<T>::value,
             std::reference_wrapper<std::remove_reference_t<T>>,
             T>{std::forward<T>(t)}]

Live Demo

but providing helper function seems more readable

like image 130
Jarod42 Avatar answered Oct 14 '22 06:10

Jarod42