在可变参数模板中复制的引用参数 [英] Reference parameter being copied in variadic template

查看:58
本文介绍了在可变参数模板中复制的引用参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Event 类,它将一组 weak_ptr(观察者)元组存储到一个函数中,该函数在触发"事件时执行.

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".

示例中的函数类型为:void(int &).也就是说,我想触发传递对值的引用的事件,让观察者更改该值并验证该值是否已更改回被观察对象中.顺便说一下,事件实现是可变的,这可能会使问题(至少是代码)复杂化.

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.

完整的回购如下.注意 assert (value != 10) 失败,即使我在事件处理程序中将该值设置为 1.

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;
}

推荐答案

Event::operator() 按值接受参数.改写如下:

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)...);
    }       
}

这篇关于在可变参数模板中复制的引用参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆