草庐IT

c++ - lambda 的生命周期在 const lambda 中捕获引用

coder 2024-02-04 原文

我有以下 API:

old_operation(stream, format, varArgs);

我想写一个适配器来编写调用如下:

stream << operation(format, varArgs);

为此,我使用了一个临时对象,它存储对 varArgs 的引用并重载 operator<<申请old_operation()如下:

template<typename ...T>
decltype(auto) storage(T&& ...t) {
   return [&](auto&& f) ->decltype(auto) {
       return std::forward<decltype(f)>(f)(t...);
   };
}

template<typename ...T>
class Operation
{
    using Storage = decltype(storage(std::declval<T>()...));
    public:
       template<typename ...Args>
       explicit Operation(Args&& ...args) : 
               mArgs(storage(std::forward<Args>(args)...)) {};
       template<class StreamType>
       StreamType& Apply(StreamType& stream)
       {
           auto f = [&](auto&& ...xs)
           {
               old_operation(stream, std::forward<decltype(xs)>(xs)...);
           }
           mArgs(f);
           return stream;
       }
   private:
       Storage mArgs;
};

template<typename ...Args>
Operation<Args...> MakeOperation(Args&&... args)
{
    return Operation<Args...>(std::forward<Args>(args)...);
}

template<class StreamType, typename ...Args>
StreamType& operator<<(StreamType& stream, Operation<Args...>&& operation)
{
    return operation.Apply(stream);
}

效果很好,但现在我需要添加一些 using namespace嵌入到操作调用中的声明:

假设我有

namespace X {namespace Y { namespace Z { int formater(double x) { return std::round(x); }}}

而且我不想为这个调用添加所有命名空间,所以我正在做类似的事情:

#define OPERATION(...) \
   [&]() { \
        using namespace ::X:Y:Z; \
        return Operation("" __VA_ARGS__); }() \

这允许我做:

stream << OPERATION(format, formater(2.3));

lambda 的问题是临时对象是在与 Apply() 不同的范围内创建的调用,即 UB。

我不知道通过向 mArgs 添加 const 限定符是否会延长捕获引用的生命周期,如前所述 here .我不确定这是否适用,我假设它们是基于堆栈的引用,并且通过将 const 限定符添加到 mArgs,该限定符将应用于捕获的引用。

最佳答案

template<typename ...T>
decltype(auto) storage(T&& ...t) {
  return [&](auto&& f) ->decltype(auto) {
    return std::forward<decltype(f)>(f)(t...);
  };
}

这是一个 haskell 风格的仿函数(好吧,一个可变的仿函数,它不是很 haskell)。它需要 Ts... 并返回类型为 ((Ts...)->U)->U 的函数,即知道如何计算函数你传递给它的参数。这使得 (Ts...)->( ((Ts...)->U)->U ) 类型的 storage 有点代数的乐趣。

我怀疑你的问题是你有你不存储的临时文件。通常不存储传递给函数的临时变量,返回值取决于这些临时变量的生命周期,导致代码脆弱。

如果你有 C++1z experimental::apply 我们可以这样做:

template<class... Ts>
decltype(auto) storage(Ts&&... ts) {
  return
    [tup=std::tuple<Ts...>(std::forward<Ts>(ts)...)]
    (auto&& f)
    ->decltype(auto) mutable
  {
    return std::experimental::apply(decltype(f)(f), std::move(tup));
  };
}

返回对 std::apply 的一次性延迟调用。 Apply 接受一个函数和一个元组,并将元组的参数传递给函数。它正确处理引用和 r/lvalue-ness。同时,元组的容器使捕获更简单,让我们可以轻松地有条件地存储右值,同时将左值保留为引用。

我认为这解决了您的问题,因为临时对象被移入元组而不是通过引用捕获,而非临时对象通过引用存储。

应该有 std::experimental::apply 实现,它比我在这里可以轻松绘制的任何东西都要好。

关于c++ - lambda 的生命周期在 const lambda 中捕获引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37545555/

有关c++ - lambda 的生命周期在 const lambda 中捕获引用的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  5. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

  8. ruby - Chef LW 资源属性默认值如何引用另一个属性? - 2

    我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我

  9. ruby - 捕获 Ruby Logger 输出以进行测试 - 2

    我有一个像这样的ruby​​类:require'logger'classTdefdo_somethinglog=Logger.new(STDERR)log.info("Hereisaninfomessage")endend测试脚本行如下:#!/usr/bin/envrubygem"minitest"require'minitest/autorun'require_relative't'classTestMailProcessorClasses当我运行这个测试时,out和err都是空字符串。我看到消息打印在stderr上(在终端上)。有没有办法让Logger和capture_io一起玩得

  10. ruby - Capistrano 中的执行、测试和捕获命令有什么区别? - 2

    关于SSHkit-Github它说:Allbackendssupporttheexecute(*args),test(*args)&capture(*args)来自SSHkit-Rubydoc,我明白execute实际上是test的别名?test之间有什么区别?,execute,capture在Capistrano/SSHKit中我应该什么时候使用? 最佳答案 执行只是执行命令。使用非0退出引发错误。测试方法的行为与execute完全相同,但是它返回bool值(true如果命令以0退出,而false否则)。它通常用于控制任务中的流程

随机推荐