【问题标题】:Reference parameter being copied in variadic template在可变参数模板中复制的参考参数
【发布时间】:2015-09-14 22:34:58
【问题描述】:

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

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

目前这是失败的。沿线某处,引用被转换为非引用或复制,但我看不到在哪里。

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

#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() 按值取 args

标签: c++ pass-by-reference variadic-templates


【解决方案1】:

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

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

【讨论】:

  • 好的,但是在可变参数包中,例如,我可能希望一些是值,一些是引用。如果我通过 &&,那还会发生吗?
  • 啊,我遇到了相反的问题。所以看来我必须在通过引用或按值传递之间做出选择。我不能混合它们,即。我的函数不能为 void (int, int &)。
  • 应该可以。 OnEvent 可以随心所欲地接受它的论点。 Event::operator() 引用的事实并没有改变这一点。
  • 是的,我刚刚用 int, int & 做了一个测试,第一个参数没有改变,第二个是。所以它有效!谢谢。
  • @Robinson void(int, int&) works perfectlyEvent::operator() 通过引用获取所有参数(适用于每个参数)并将它们传递给处理函数,该处理函数通过引用或值获取它们,没关系。
猜你喜欢
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 2017-02-01
  • 2019-02-04
  • 2013-09-22
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多