在嵌套的lambdas中捕获通用可调用对象 - 总是前进?

时间:2016-04-22 11:02:11

标签: c++ lambda c++14 perfect-forwarding callable-object

我的代码库中有各种函数,它们接受一个通用的可调用对象,然后在调用之前将它传递给一系列嵌套的lambdas。例如:

template <typename TF>
void interface(TF&& f)
{
    nested0([/*...*/]()
        {
            nested1([/*...*/](auto& x)
                {
                    nested2([&x, /*...*/]()
                        {
                            f(x);
                        });
                });
        });
}

请注意,interface通过转发引用(以前称为通用引用)来获取类型为TF的可调用对象。可调用对象通常是具有各种捕获变量的lambda,包括值和引用。

在保持正确性的同时,在嵌套lambda中捕获f的最佳方式(在性能方面)是什么?

我可以想到三个选择:

  1. 通过复制捕获f

    nested0([f]()
    {
        nested1([f](auto& x)
            {
                nested2([&x, f]()
                    {
                        f(x);
                    });
            });
    });
    

    可能导致不必要的副本,如果捕获的对象为mutable,则可能导致错误行为。

  2. 通过引用捕获f

    nested0([&f]()
    {
        nested1([&f](auto& x)
            {
                nested2([&x, &f]()
                    {
                        f(x);
                    });
            });
    });
    

    似乎是合理的,但如果任何嵌套的lambda执行的行动超过f的所有者,则可能会导致问题。想象一下,如果nested2的主体在一个单独的线程中执行 - f已经超出了范围。

  3. 制作lambdas mutable并通过完美转发捕获。

    #define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
    
    nested0([f = FWD(f)]() mutable
    {
        nested1([f = FWD(f)](auto& x) mutable
            {
                nested2([&x, f = FWD(f)]() mutable
                    {
                        f(x);
                    });
            });
    });
    

    lambdas必须是mutable,因为我们可能会将f从lambda移动到另一个lambda。这种方法似乎可以避免不必要的副本,并在可调用对象需要比原始调用者更长时正确移动它。

  4. 选项3总是最好的,还是有任何潜在的缺点? ......或者可能没有“最佳和正确”的方式(关于可调用的知识)对象是必需的)

1 个答案:

答案 0 :(得分:1)

正如评论中所提到的,如果对这个问题给出如此糟糕的背景,很难说 也就是说,在我看来,最好的解决方案是通过引用捕获所有内容,并在需要副本时打破此逻辑,其目的是比f的生命周期更长,例如:

nested0([&f]() {
    n1([&f](auto& x) {
        n2([&x,
                // get a local copy of f
                f{std::forward<TF>(f)}]() {
            f(x);
        });
    });
});

无论如何,对于这样的问题没有经验法则 最佳解决方案可能与实际问题紧密相关 照常。很公平。