1

I want to initialize std::function object from a function object. Here is an example of how I can do it:

#include <functional>

struct Func {
    void operator()() const
    {}
};

int main()
{
   std::function<void()> f = Func();
}

This works fine but if I add some nocopyable member to Func, the example fails to compile:

#include <functional>
#include <memory>

struct Func {
    void operator()() const
    {}

    std::unique_ptr<int> ptr;
};

int main()
{
   std::function<void()> f = Func();
}

with error message:

In file included from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/functional:59,
                 from prog.cc:1:
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/std_function.h: In instantiation of 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = Func; std::false_type = std::integral_constant<bool, false>]':
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/std_function.h:211:16:   required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = Func]'
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/std_function.h:677:19:   required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = Func; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = void; _ArgTypes = {}]'
prog.cc:13:35:   required from here
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/std_function.h:176:6: error: use of deleted function 'Func::Func(const Func&)'
  176 |      new _Functor(*__source._M_access<const _Functor*>());
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:4:8: note: 'Func::Func(const Func&)' is implicitly deleted because the default definition would be ill-formed:
    4 | struct Func {
      |        ^~~~
prog.cc:4:8: 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<int>]'
In file included from /opt/wandbox/gcc-9.3.0/include/c++/9.3.0/memory:80,
                 from prog.cc:2:
/opt/wandbox/gcc-9.3.0/include/c++/9.3.0/bits/unique_ptr.h:414:7: note: declared here
  414 |       unique_ptr(const unique_ptr&) = delete;
      |       ^~~~~~~~~~

I know that std::unique_ptr is nocopyable and therefore whole Func is also nocopyable. But I don't want it to be copied to initialize std::function. I want to move temporary object Func() into std::function. How I can do it?

ks1322
  • 33,961
  • 14
  • 109
  • 164
  • 1
    Shouldn't `std::function` be copy-constructible? https://en.cppreference.com/w/cpp/utility/functional/function – fas May 02 '20 at 16:33
  • 4
    You can't. `std::function`s themselves are copyable. Therefore, whatever you put into a `std::function` must be copyable too. That's how it works. The most you can do is implement a copy-constructor for your class that does whatever you want to do with the unique_ptr in the class. Or, make it a shared_ptr, and call it a day. – Sam Varshavchik May 02 '20 at 16:34
  • Does std::move() help, if you just want to move? What happens when you try it? – Jeffrey May 02 '20 at 16:37
  • @Jeffrey, no `std::move` does not change anything, the example still not compiles. – ks1322 May 02 '20 at 16:40
  • @SamVarshavchik, for now I am using a `shared_ptr` but I was thinking of a better solution. – ks1322 May 02 '20 at 16:43
  • There is no "better solution". A class is either copyable, or it's not copyable. There are no other possibilities. `std::function` requires a copyable object. There's no such thing as a class that's not copyable, but somehow it's also copyable only for `std::function`'s purpose. – Sam Varshavchik May 02 '20 at 17:02

0 Answers0