Reference parameter being copied in variadic template

回眸只為那壹抹淺笑 提交于 2019-12-13 18:30:46

问题


I have an Event class that stores a set of tuples of weak_ptr (the observer) to a function that gets executed when the event is "fired".

The function type is: void(int &) in the example. That is to say, I want to fire the event passing a reference to a value, to have the observer change that value and to verify that the value was changed back in the observed object. The event implementation is variadic by the way, which may complicate the issue (at least the code).

At the moment this is failing. Somewhere along the line the reference is being converted to a non-reference or copied, but I cannot see where.

Full repo is below. Note assert (value != 10) fails, even though I set the value to 1 in the event handler.

#include <memory>
#include <tuple>
#include <vector>
#include <cassert>
#include <functional>

template<class FunctionPrototype>
class Event
{
public:

    template<typename... Args>
    void operator()(Args... args)
    {
        for (auto const & listener : Listeners)
        {
            if (auto locked = std::get<0>(listener).lock())
                std::get<1>(listener)(args...);
        }       
    }

    template<typename P, typename Q, typename R, typename... Args>
    void Attach(P(Q::*f)(Args...), std::shared_ptr<R> const & p)
    {
        auto w = std::weak_ptr<R>(p);

        auto l = [w, f](Args... args) {
            if (auto locked = w.lock())
                return (*locked.get().*f)(args...);
            else
                return P();
        };

        Listeners.push_back(std::make_tuple(std::weak_ptr<void>(w), l));        
    }

    typedef std::tuple<std::weak_ptr<void>, std::function<FunctionPrototype>> event_tuple;

    std::vector<event_tuple> Listeners;
};

class Observed : public std::enable_shared_from_this < Observed >
{
public:

    int value;

    void Fire()
    {
        value = 10;

        TheEvent(value);

        assert(value != 10);
    }

    Event<void(int &)> TheEvent;
};

class Observer : public std::enable_shared_from_this<Observer>
{
public:

    void Attach(std::shared_ptr<Observed> const & observed)
    {
        observed->TheEvent.Attach(&Observer::OnEvent, shared_from_this());
    }

    void OnEvent(int & value)
    {
        assert(value == 10);

        value = 1;
    }
};

int main(void)
{
    auto observed = std::make_shared<Observed>();
    auto observer1 = std::make_shared<Observer>();

    observer1->Attach(observed);
    observed->Fire();

    return 0;
}

回答1:


Event::operator() takes arguments by value. Rewrite it as follows:

template<typename... Args>
void operator()(Args&&... args)
{
    for (auto const & listener : Listeners)
    {
        if (auto locked = std::get<0>(listener).lock())
            std::get<1>(listener)(std::forward<Args>(args)...);
    }       
}


来源:https://stackoverflow.com/questions/31099155/reference-parameter-being-copied-in-variadic-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!