cross-platform / dspatch

The Refreshingly Simple Cross-Platform C++ Dataflow / Patching / Pipelining / Graph Processing / Stream Processing / Reactive Programming Framework
https://flowbasedprogramming.com/
BSD 2-Clause "Simplified" License
216 stars 44 forks source link

MoveValue without copy constructor #67

Closed pawelswoboda closed 6 months ago

pawelswoboda commented 6 months ago

I have a class with only a move constructor but without a copy constructor. When I use it as a an output from a component, I get an error. Below I give a minimal example where this happens together with the compilation error. My platform is macOS Sonoma 14.2.1 on a M2 processor, and compilation is done using Apple clang version 15.0.0 (clang-1500.1.0.2.5)

Code:

{ class movable_class { public: movable_class() {} movable_class(movable_class && other) {}; };

class test_component final : public DSPatch::Component {
    public:
        test_component()
        {
            SetInputCount_(0);
            SetOutputCount_(1);
        }
        void Process_(DSPatch::SignalBus& inputs, DSPatch::SignalBus& outputs) override
        {
            movable_class x;
            outputs.MoveValue(0, std::move(x));
        }
};
auto c = std::make_shared<test_component>();

auto circuit = std::make_shared<Circuit>();
circuit->AddComponent(c);
circuit->Tick();

}

Compilation error:

In file included from /Users/pswoboda/repo/dspatch/include/DSPatch.h:31: In file included from /Users/pswoboda/repo/dspatch/include/dspatch/Circuit.h:31: In file included from /Users/pswoboda/repo/dspatch/include/dspatch/Component.h:31: In file included from /Users/pswoboda/repo/dspatch/include/dspatch/SignalBus.h:33: /Users/pswoboda/repo/dspatch/include/fast_any/any.h:279:58: error: object of type 'movable_class' cannot be assigned because its copy assignment operator is implicitly deleted static_cast<value_t*>( _value_holder )->value = std::forward( value ); ^ /Users/pswoboda/repo/dspatch/include/dspatch/SignalBus.h:172:31: note: in instantiation of function template specialization 'fast_any::any::emplace' requested here _signals[signalIndex].emplace( std::forward( newValue ) ); ^ /Users/pswoboda/repo/dspatch/tests/main.cpp:982:13: note: in instantiation of function template specialization 'DSPatch::SignalBus::MoveValue' requested here outputs.MoveValue(0, std::move(x)); ^ /Users/pswoboda/repo/dspatch/tests/main.cpp:959:4: note: copy assignment operator is implicitly deleted because 'movable_class' has a user-declared move constructor movable_class(movable_class && other) ^

Thank you for any help!

MarcusTomlinson commented 6 months ago

Hi @pawelswoboda, thanks for the interest in DSPatch.

Signal types have a strict requirement that they must be both copy constructible and assignable. Sorry that isn't made clear.

This requirement comes from the fast_any type, and is subsequently the reason it outperforms boost/std::any.

MarcusTomlinson commented 6 months ago

In other words, for your type to be used as a signal it must at least define a copy constructor and a copy assignment operator.

For it to be most effective it'd also define a move constructor and a move assignment operator:

class movable_class
{
public:
    movable_class()
    {
        // ...
    }
    movable_class( const movable_class& other )
    {
        // ...
    };
    movable_class( movable_class&& other )
    {
        // ...
    };
    movable_class& operator=( const movable_class& other )
    {
        // ...
        return *this;
    };
    movable_class& operator=( movable_class&& other )
    {
        // ...
        return *this;
    };
};