c++ - 如何使用 lambda 来进行 std::invoke 惰性求值?

标签 c++ lambda callback c++17 c++20

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/

相关文章:

c++ - 编译时检查连续函数调用

c# - 在这个基本的 Contains<>() 扩展方法和 Lambda 表达式方面需要帮助

c# - 我应该如何将 lambda 表达式转换为代码(文本)?

C++ Qt QGraphicsWidget 背景

c++ - 删除在 DLL 中创建的对象

.net - 如何使用 Moq 测试 lambda 函数?

javascript - 向回调函数添加额外的参数

c++ - 指向不同类成员函数的指针

android - onDestroy() 在 Activity 被用户杀死时没有被调用?

c++ - 在 C++ 中动态改变指针的大小