10

A lambda can be easily converted to std::function though this seems to be impossible when the lambda uses generalized capture with a unique_ptr. Likely an underlying std::move is missing. Is there a workaround for this or is this a known issue?

#include <iostream>
#include <memory>
#include <functional>

using namespace std;

int main()
{
    auto lambdaGeneralizedCaptureOk = [t = std::make_unique<int>(1)]()
      {
        std::cout << *t << std::endl;
      };
    lambdaGeneralizedCaptureOk();
    
    // error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete]’
    std::function<void()> lambdaToFunctionGeneralizedCaptureNok = [t = std::make_unique<int>(2)]()
      {
        std::cout << *t << std::endl;
      };
    lambdaToFunctionGeneralizedCaptureNok();
    
    return 0;
}
cigien
  • 57,834
  • 11
  • 73
  • 112
  • you should include the error message in the question. The "is it a known issue" part can be asnwered by reading the error message – 463035818_is_not_an_ai Nov 15 '22 at 15:33
  • 1
    https://stackoverflow.com/questions/59967794/rationale-behind-making-stdfunction-require-copy-constructor – Mat Nov 15 '22 at 15:35

2 Answers2

12

Is there a workaround for this or is this a known issue?

std::function requires that the underlying callable must be copyable, since the lambda object in your example is move-only, this is ill-formed.

It's worth noting that C++23 introduced move_only_function, which does exactly what you need

std::move_only_function<void()> lambdaToFunctionGeneralizedCaptureNok = 
  [t = std::make_unique<int>(2)]() {
    std::cout << *t << std::endl;
   };

Demo

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • 3
    @CaptainGiraffe Both MSVC and libstdc++ have implemented `move_only_function`. – 康桓瑋 Nov 15 '22 at 15:40
  • 1
    So C++ realized that Rust had it figured out with the `FnOnce` / `Fn` / `FnMut` distinction and made its own version of `FnOnce`. It's so fascinating to see the convergent evolution of these two languages. – Silvio Mayolo Nov 16 '22 at 00:10
2

The workaround is to use a std::shared_ptr instead.

doron
  • 27,972
  • 12
  • 65
  • 103