Quentamia
Quentamia

Reputation: 3294

Virtual functions, std::function, and non-copyable objects

Below is a simplified, contrived example of what I'm seeing.

Problem

I have a virtual function that accepts a std::function object.

class Foo {
    virtual void bar(std::function<void()> &&f);
};

This works fine until I need to capture a non-copyable variable.

auto ptr = std::make_unique<int>();

Foo f{};
f.bar([ptr = std::move(ptr)]() {
    // Use ptr...
});

Question

I understand why this doesn't work: std::function doesn't allow non-copyable objects. I also know that, in most cases, the fix would be fo have bar accept a template, something like the following:

template<typename F>
bar(F &&f);

In my specific situation, bar must be virtual. Does anyone know of a workaround?

Upvotes: 0

Views: 99

Answers (1)

Allen Stubberud
Allen Stubberud

Reputation: 21

  1. Use shared_ptr because it can be copied.
  2. Use references or raw pointers and manage the lifetime of the functor manually.
  3. Create visitor classes and use virtual functions (very old-school).
    class FooVisitor {
    public:
      virtual ~FooVisitor() = default;
      virtual void Invoke() = 0;
    };
    
    class FooVisitorImpl : public FooVisitor {
      std::unique_ptr<int> mState;
    
    public:
      FooVisitorImpl(std::unique_ptr<int> aState)
          : mState(std::move(aState))
      {}
    
      void Invoke() final {
        // callback code
      }
    };
    
    // main code
    Foo x;
    FooVisitor v(std::make_unique<int>(0));
    x.bar(v);
    
    // or, if Foo must retain the callback
    Foo x;
    auto v = std::make_unique<FooVisitor>(/* ... */);
    x.bar(std::move(v));
    

Upvotes: 2

Related Questions