C ++ 14 Lambda - Conditional capture by reference or value

Is it possible to conditionally choose a lambda capture method based on compilation time information? For instance...

auto monad = [](auto && captive) { return [(?)captive = std::forward<decltype(captive)>(captive)](auto && a) { return 1; }; }; 

I want to capture by reference if decltype(captive) is std::reference_wrapper and everything else is by value.

+6
source share
2 answers

The lambda capture type cannot be controlled by template-dependent names.

However, you could achieve the desired effect by delegating the creation of an internal lambda to an overloaded function:

 template<class T> auto make_monad(T&& arg) { return [captive = std::forward<T>(arg)](auto&& a) { std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; return 1; }; } template<class T> auto make_monad(std::reference_wrapper<T> arg) { return [&captive = static_cast<T&>(arg)](auto&& a) { std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; return 1; }; } int main() { auto monad = [](auto&& captive) { return make_monad(std::forward<decltype(captive)>(captive)); }; int n = 1; monad(1)(1); monad(n)(2); monad(std::ref(n))(3); } 

Outputs:

 make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int] 1 make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int&] 2 make_monad(std::reference_wrapper<_Tp>)::<lambda(auto:2&&)> [with auto:2 = int; T = int] 3 

I do not want to capture the reference_wrapper by reference, I want to capture the link that it holds by reference. A wrapper link looks best like a link, but since the call operator (operator "a", ".") Cannot be overloaded, at the end of the day it fails.

In this case, you do not need to change the capture type for std::reference_wrapper<T> . Instead, you may like to capture it by value, like any other argument, and on the usage site, expand the argument first:

 template<class T> T& unwrap(T& t) { return t; } template<class T> T& unwrap(std::reference_wrapper<T> t) { return t; } auto monad = [](auto && captive) { return [captive](auto && a) { // <--- Capture by value. auto& captive_ref = unwrap(captive); // <--- Unwrap before usage. return 1; }; }; 
+4
source

It does not answer your question, but your comment is how to use operator . :

You can add these two overloads:

 template <typename T> T& get_reference_object(T&& t) { return t; } template <typename T> T& get_reference_object(std::reference_wrapper<T> t) { return t.get(); } 

and then you can use get_reference_object(arg).foo inside your lambda:

 auto monad = [](auto && captive) { return [captive = captive](auto&& a) { return get_reference_object(captive).foo(a); }; }; 

Living example .

+1
source

Source: https://habr.com/ru/post/978736/


All Articles