在 C++ 中模拟 lambda 的复制赋值运算符

2023-12-10

这个问题有两个部分

Firstly,有人可以解释 C++ 禁用 lambda 的复制赋值运算符背后的基本原理吗?如果您要允许复制构造函数,为什么不允许复制赋值运算符呢?

Secondly,如何在不强迫人们编写 C++03 风格函子或使用 std::function 的情况下最好地克服这个限制(我正在处理的函数很小,我希望编译器尽可能内联它们) ?

背景: 我正在尝试在 a 中实现类似 flat_map 的操作我正在写的流处理库,类似于Scala或其他函数式语言中的flatMap。因此,我需要创建一个迭代器列表的迭代器。每次取消引用 flat_map 迭代器时,都会执行与内部迭代器关联的 lambda。每次内迭代器到达末尾时,外迭代器都需要切换内迭代器。由于内部迭代器包含 lambda,因此没有复制赋值运算符,因此无法切换它。从技术上讲,我可以使用动态分配来解决问题,这样我总是调用复制构造函数,但这似乎不是正确的方法。以下是可能有助于突出问题的代码片段:

template <typename Iter>
class flat_map_iterator {
public:
  flat_map_iterator& operator++() {
    ++it_inner_;
    if (it_inner_ == (*it_outer_).end()) {
      ++it_outer_;
      // ERROR: cannot be assigned because its copy assignment operator is implicitly deleted
      it_inner_ = (*it_outer_).begin();
    }
    return *this;
  }
private:
  Iter it_outer_; 
  typename Iter::value_type::iterator it_inner_;
};

Edit:

感谢您的快速回复。这是一个用例示例:

 int res = ftl::range(1, 4).map([](int a){
     return ftl::range(a, 4).map([a](int b){
         return std::make_tuple(a, b);
     });
 })
 .flat_map([](std::tuple<int, int> x){ return std::get<0>(x) * std::get<1>(x); })
 .sum();

 assert(res, 25);

The ftl::range(begin, end)函数返回范围内的惰性迭代器[begin, end).


并不是说C++禁用了lambda本身的复制赋值运算符,而是默认情况下lambda对象中的成员保存为const,然后赋值运算符基本上无法对它们进行赋值,因此不会生成它。如果你想要 lambdanot将成员保留为常量,您可以使用[...](...) mutable {...} syntax.

另一件事是我不完全确定分配 lambda 会得到什么。我的意思是,如果您要重复使用 lambda 类型(和功能)并简单地将其绑定到不同的变量,那么您已经在使用漂亮的 lambda 捕获语法,并且还可以将其作为普通的函数对象。将一种类型的 lambda 分配给另一种类型是不可能的。这意味着当您按值保存 lambda 本身时,无法提供不同的 lambda 实现。

如果这是still你想要什么,我认为动态分配(例如使用unique_ptr)是公平的游戏。

如果你真的想避免它,你可以手动解构并重新构造你的 lambda,如下所示example说明:

#include <iostream>

template <class T>
struct LambdaContainer {
    LambdaContainer(const T& lambda)
        : lambda{lambda} {}

    void resetLambda(const T& lambda) {
        this->lambda.~T();
        new (&this->lambda) T{lambda};
    }

    T lambda;
};

int main()
{
    int i = 1;

    auto l = [=]() {
        std::cout << i;
    };

    using LT = decltype(l);

    LambdaContainer<LT> lc{l};

    lc.resetLambda(l);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 C++ 中模拟 lambda 的复制赋值运算符 的相关文章

随机推荐