我试图弄清楚,即使它不是转发(=通用)引用,我在以下代码中使用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问题,我遇到了很多麻烦。
答案 0 :(得分:1)
std::move
不移动std::forward
不转发。
std::forward
是条件移动。如果std::forward<T>
是值或右值参考,则会T
移动。
当你想要移动args...
时,这就相同了,所以这里是合适的。
这些注释应该是一个好主意,就像在简单转发引用之外使用std::forward
的任何情况一样。