使用std :: forward进行非转发引用

时间:2018-02-20 12:45:33

标签: c++ c++11 c++17

我试图弄清楚,即使它不是转发(=通用)引用,我在以下代码中使用std::forward也是有意义的。请原谅代码量,但这是我想要实现的精简版。

template <class... Args>
class event_dispatcher {
private:
  using func_t = std::function<bool(Args...)>;

public: 
  bool operator()(Args... args) const {
    for (auto& f : funcs) {
      if (!f(args...))
        return false;
    }
    return true;
  }

  template <class F>
  std::enable_if_t<std::is_invocable_r_v<bool, F, Args...>>
  add(F&& f) {
    funcs.emplace_back(std::forward<F>(f));
  }

  template <class F>
  std::enable_if_t<!std::is_invocable_r_v<bool, F, Args...> && std::is_invocable_v<F, Args...>>
  add(F&& f) {
    add([f_ = std::forward<F>(f)](Args... args){
         std::invoke(f_, std::forward<Args>(args)...); // <-- this is the one I am asking about!
         return true;
       });
  }

private:
  std::vector<func_t> funcs;
};

这个想法是,如果传递给add()的callable没有返回bool,我们会将它包装在一个lambda中。

现在,如果我直接传递args...,它将始终有效,但如果Args中的任何一个是右值,那么它将不必要地复制而不是移动。如果我使用std::move(args)...,如果Args中的任何一个是左值,它将无效。在这里使用std::forward<Args>(args)...似乎解决了这些问题,并且在任何情况下都尽可能高效地工作,但我担心因为我使用std::forward进行非转发引用而遗漏了一些东西,并且一般情况下围绕整个参考折叠/右值参考/ std :: move / std :: forward问题,我遇到了很多麻烦。

1 个答案:

答案 0 :(得分:1)

std::move不移动std::forward不转发。

std::forward条件移动。如果std::forward<T>是值或右值参考,则会T移动。

当你想要移动args...时,这就相同了,所以这里是合适的。

这些注释应该是一个好主意,就像在简单转发引用之外使用std::forward的任何情况一样。