c++ - 将 lambda 作为参数的约定
问题描述
我正在编写一个 C++ 应用程序,并在 lambda 参数上抽象了一个方法。我最初使用以下签名:
void atomically(void (*block)(T& value, bool& retry))
但是我发现您不能将任意 lambda 作为函数指针传递—— lambda 必须没有捕获。我可以使用
void atomically(const std::function<void (T&, bool&)>& block)
除了在这部分代码中非常重要的是,我们避免在堆上分配,并创建一个std::function
可能的分配。(是否/何时可以保证?)
最后,我可以使用:
template<class F>
void atomically(const F& block) {
// use block() as if it had been declared as above
}
除了我觉得这是不可接受的,因为它允许block
通过值而不是通过引用来获取参数,这将是一个容易犯的错误并且调试起来非常微妙。
将 lambda 作为参数的正确约定是什么?或者,在最终的模板解决方案中,有没有办法确保block
通过引用获取其参数?
解决方案
您可能想要一些function_view
(取自vittorioromeo)(顾名思义,没有所有权,所以不要存储它):
template <typename TSignature>
class function_view;
template <typename TReturn, typename... TArgs>
class function_view<TReturn(TArgs...)> final
{
private:
using signature_type = TReturn(void*, TArgs...);
void* _ptr;
TReturn (*_erased_fn)(void*, TArgs...);
public:
template <typename T, typename = std::enable_if_t<
std::is_callable<T&(TArgs...)>{} &&
!std::is_same<std::decay_t<T>, function_view>{}>>
function_view(T&& x) noexcept : _ptr{(void*)std::addressof(x)}
{
_erased_fn = [](void* ptr, TArgs... xs) -> TReturn {
return (*reinterpret_cast<std::add_pointer_t<T>>(ptr))(
std::forward<TArgs>(xs)...);
};
}
decltype(auto) operator()(TArgs... xs) const
noexcept(noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...)))
{
return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
}
};
然后你可以使用:
void atomically(const function_view<void (T&, bool&)>& block)
推荐阅读
- sql - 如何实现连接以合并两个表 FULL OUTER JOIN 并避免重复?
- javascript - 如何更改引导模式的输入字段的值
- python - 如何将文本分类到每一行数据框?
- c++ - 将非静态函数绑定到回调的问题
- angular - 如何在 Angular 6 中添加反应自定义元素
- asp.net-web-api - 无法在 Visual Studio 2019 中添加 wep.api 控制器
- php - 其他产品页面的重复值不断删除
- firebase - 在 Firebase 身份验证中,“最近”经过身份验证意味着多久以前?
- c# - 从 ASP.NET 应用程序通过 Google API 发送电子邮件
- python - Python:Pandas Grouper() 函数时间戳选择