C++11 引入 lambdas让我们可以更轻松地在 C++ 中实现延迟计算,所以我想知道是否可以以这种方式制作 std::invoke?
根据 cppreference,std::invoke
是通过以下方式实现的:
template <typename F, typename... Args>
decltype(auto) invoke(F&& f, Args&&... args)
noexcept(...)
{
return detail::INVOKE(std::forward<F>(f), std::forward<Args>(args)...);
}
我们可以在这里看到很多完美转发,我想做这个惰性评估。这是我的实现:
template <typename F, typename... Args>
constexpr auto delay_invoke(F&& f, Args&&... args) {
return [&]() -> decltype(auto) {
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
};
}
它通过了我在 wandbox 的测试。由于这个 lambda 是通过引用捕获的,所以我认为这种方式存在悬空引用问题,所以我尝试通过值捕获的第二种实现:
template <typename F, typename... Args>
constexpr auto delay_invoke(F&& f, Args&&... args) {
return [=]() mutable -> decltype(auto) {
return std::invoke(static_cast<F&&>(f), static_cast<Args&&>(args)...);
};
}
它也通过了我的测试。 我对吗?您有更好的实现或其他好的解决方案吗?谢谢!
最佳答案
Do you have nicer implementation or other good solution?
您的两个示例要么通过引用捕获所有内容(这很糟糕,因为悬而未决,尤其是在这样的用例中),要么复制所有内容(这比另一个,但效率很低,因为某些参数可能是右值)。您要做的就是转发整个包。然而,在 C++17 中,“通过向前”捕获包非常乏味。值得庆幸的是,在 C++20 中,感谢 P0780 ,这会变得容易很多。该论文中的激励示例与您的示例非常接近。
C++17 版本的前向捕获需要一个元组
(或类似的东西):
template <typename... Args>
auto delay_invoke(Args&&... args) {
return [tup=std::make_tuple(std::forward<Args>(args)...)]() mutable -> decltype(auto) {
return std::apply([](auto&... args) -> decltype(auto) {
return std::invoke(static_cast<Args&&>(args)...);
}, tup);
};
}
C++20 版本更加简单:
template <typename... Args>
auto delay_invoke(Args&&... args) {
return [...args=std::forward<Args>(args)]() mutable -> decltype(auto) {
return std::invoke(std::forward<Args>(args)...);
};
}
关于c++ - 如何使用 lambda 来进行 std::invoke 惰性求值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56925234/