Ссылочный параметр Rvalue истекает при передаче через std::forward?

У меня есть этот код, который пытается совершенную пересылку пакета параметров шаблона в std::function через промежуточный класс:

#include <functional>
#include <vector>
#include <algorithm>
#include <iterator>
#include <memory>
#include <iostream>

template <typename ...Arguments>
class CSignal
{
public:
    typedef std::function<void (Arguments...)> SignalFunction;
public:
    void connect(const SignalFunction& target)
    {
        m_connections.emplace_back(std::make_shared<SignalFunction>(target));
    }

    template <typename ...ActualArguments>
    void invoke(ActualArguments&&... args) const
    {
        for (auto& connection: m_connections)
            if (connection)
                (*connection)(std::forward<ActualArguments>(args)...);
    }

private:
    std::vector<std::shared_ptr<SignalFunction>> m_connections;
};


struct A
{
    void f() {std::cout << __FUNCTION__ << "\n";}
};

void test(std::shared_ptr<A> ptr)
{
    if (ptr)
        ptr->f();
}

int main()
{
    CSignal<std::shared_ptr<A>> signal;
    signal.connect(test);
    signal.connect(test);

    signal.invoke(std::make_shared<A>());

    return 0;
}

Проблема: test вызывается дважды, и во второй раз это называется его параметром empty указатель. Зачем?

Если я удалю std::forward проблема исчезает, но это не то, что я хочу.

1 ответ

Решение

Да; std::forward делает то же самое, что и std::move когда ActualArguments не является ссылочным типом.

С точки зрения срока годности, forward нужно относиться так же, как move, Как правило, вы не forward или же move внутри петли.

Если вы хотите переместить параметр на последней итерации цикла, вам придется вырвать его из цикла. Это, вероятно, означает, что вы не используете синтаксис диапазона. Однако вы можете спросить, является ли это полезной оптимизацией, и подумать о том, чтобы сохранить ее на потом, когда будет доступно больше данных о производительности.

Другие вопросы по тегам