Home > database >  Pass a lambda which captures a unique_ptr to another function
Pass a lambda which captures a unique_ptr to another function

Time:11-16

I want to pass a mutable lambda which captures a unique_ptr to another function as shown in the code snippet below.

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

struct Adder {
    Adder(int val1, std::unique_ptr<int> val2) : val1_(val1), val2_(std::move(val2)) {
    }

    int Add() {
        return val1_   *val2_;
    }

    int val1_;
    std::unique_ptr<int> val2_;
};

void CallAdder(std::function<int ()> func) {
    std::cout << func() << "\n";
}

int main() {
    auto ptr = std::make_unique<int>(40);
    int byRef = 2;
    auto lam = [&, p = std::move(ptr)]() mutable
    {
        return Adder(byRef, std::move(p)).Add();
    };

    CallAdder(std::move(lam));
}

Above code gives me a deleted copy constructor error for the lambda as follows.

$ clang  -14 -o lam lambda.cc
In file included from lambda.cc:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/functional:59:
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/bits/std_function.h:161:10: error: call to implicitly-deleted copy constructor of '(lambda at lambda.cc:25:16)'
            new _Functor(*__source._M_access<const _Functor*>());
                ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/bits/std_function.h:196:8: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at lambda.cc:25:16)>::_M_clone' requested here
              _M_clone(__dest, __source, _Local_storage());
              ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/bits/std_function.h:283:13: note: in instantiation of member function 'std::_Function_base::_Base_manager<(lambda at lambda.cc:25:16)>::_M_manager' requested here
            _Base::_M_manager(__dest, __source, __op);
                   ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/bits/std_function.h:611:33: note: in instantiation of member function 'std::_Function_handler<int (), (lambda at lambda.cc:25:16)>::_M_manager' requested here
            _M_manager = &_My_handler::_M_manager;
                                       ^
lambda.cc:30:15: note: in instantiation of function template specialization 'std::function<int ()>::function<(lambda at lambda.cc:25:16), void, void>' requested here
    CallAdder(std::move(lam));
              ^
lambda.cc:25:20: note: copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor
    auto lam = [&, p = std::move(ptr)]() mutable
                   ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c  /10/bits/unique_ptr.h:468:7: note: 'unique_ptr' has been explicitly marked deleted here
      unique_ptr(const unique_ptr&) = delete;
      ^

I also tried passing lambda as a reference as per cannot pass deleted lambda function with move? but I was getting a type error which complains about it not being able to typecheck the lambda against the std::function in the CallAdder signature. How would I fix this error?

CodePudding user response:

You can template CallAdder on a function parameter.

[Demo]

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

struct Adder {
    Adder(int val1, std::unique_ptr<int> val2)
        : val1_(val1), val2_(std::move(val2)) {}

    int Add() { return val1_   *val2_; }

    int val1_;
    std::unique_ptr<int> val2_;
};

template <typename F>
void CallAdder(F&& func) { std::cout << std::forward<F>(func)() << "\n"; }

int main() {
    auto ptr = std::make_unique<int>(40);
    int byRef = 2;
    auto lam = [&byRef, p = std::move(ptr)]() mutable {
        return Adder(byRef, std::move(p)).Add();
    };

    CallAdder(std::move(lam));
}

// Outputs: 42

Or just:

[Demo]

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

struct Adder {
    Adder(int val1, std::unique_ptr<int> val2)
        : val1_(val1), val2_(std::move(val2)) {}

    int Add() { return val1_   *val2_; }

    int val1_;
    std::unique_ptr<int> val2_;
};

void CallAdder(std::function<int()> func) { std::cout << func() << "\n"; }

int main() {
    auto ptr = std::make_unique<int>(40);
    int byRef = 2;
    auto lam = [&]() {
        return Adder(byRef, std::move(ptr)).Add();
    };

    CallAdder(lam);
}
  • Related