Light weight C++ Signals/Slots or Event System
Sink arguments (objects we want to make a copy of and store internally) are generally passed by value, then moved into place, so the add function can take its parameter by value rather than const&amp;.
We could perhaps make fp public with a name like Function, and use it for the add function parameter.
raise will make unnecessary copies of the arguments. We can avoid that with perfect forwarding.
We don't need to copy the weak_ptr in the raise lambda, we can use a const&amp;. We also don't need to specify the return value.


.

#include &lt;forward_list&gt;
#include &lt;functional&gt;
#include &lt;memory&gt;

template &lt;class... FuncArgs&gt;
class Signal
{   
public:

    using Function = std::function&lt;void(FuncArgs...)&gt;;
    using Listener = std::shared_ptr&lt;Function&gt;;

    Listener add(Function cb) {
        auto const result = std::make_shared&lt;Function&gt;(std::move(cb));
        listeners.push_front(result);
        return result;
    }

    template&lt;class... Args&gt;
    void raise(Args&amp;&amp;... args) {
        listeners.remove_if([&amp;args...](std::weak_ptr&lt;Function&gt; const&amp; e) {
            if (auto f = e.lock()) {
                (*f)(std::forward&lt;Args&gt;(args)...);
                return false;
            }
            return true;
        });
    }

private:

    std::forward_list&lt;std::weak_ptr&lt;Function&gt;&gt; listeners;
};

#include &lt;iostream&gt;

struct Noisy
{
    Noisy() = default;

    Noisy(Noisy const&amp;) { std::cout &lt;&lt; "copy\n"; }
    Noisy&amp; operator=(Noisy const&amp;) { std::cout &lt;&lt; "copy assign\n"; return *this; }

    Noisy(Noisy&amp;&amp;) { std::cout &lt;&lt; "move\n"; }
    Noisy&amp; operator=(Noisy&amp;&amp;) { std::cout &lt;&lt; "move assign\n"; return *this; }
};

int main()
{
    {
        auto s = Signal&lt;int&gt;();
        auto const l = s.add([] (int v) { std::cout &lt;&lt; "value: " &lt;&lt; v &lt;&lt; std::endl; });
        s.raise(5);
    }
    {
        auto s = Signal&lt;Noisy const&amp;&gt;();
        auto const l = s.add([] (Noisy const&amp;) { });
        auto const n = Noisy();
        s.raise(n);
    }
}