我想知道我是否使用了 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()
不返回 bool
,我们将把它包装在一个 lambda 中。
现在,如果我只是通过 args...
直接,它将始终有效,但如果Args
中的任何一个|是右值,那么它将不必要地进行复制而不是移动。如果我改为使用 std::move(args)...
如果Args
中的任何一个,它将不起作用是一个左值。使用 std::forward<Args>(args)...
这里似乎解决了这些问题并在任何情况下都尽可能高效地工作,但我担心我在使用 std::forward
时遗漏了一些东西。对于非转发引用,一般来说,我在思考整个引用折叠/右值引用/std::move/std::forward 问题时遇到了很多麻烦。
最佳答案
std::move
不动std::forward
不转发。
std::forward
是一个有条件的举动。 std::forward<T>
如果 T
移动是值或右值引用。
这与您要移动的时间一致 args...
, 所以在这里是合适的。
按照这些行进行评论应该是个好主意,因为在您使用 std::forward
的任何情况下在简单的转发引用之外。
关于c++ - 将 std::forward 用于非转发引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48885599/