【问题标题】:Using functor in lambda在 lambda 中使用仿函数
【发布时间】:2021-03-04 19:46:48
【问题描述】:

我对在 C++ 中使用函子和 lambda 的一些语法感到困惑。

我将函子定义为:

class paint : public OpCode {
public:
    using OpCode::OpCode;

    void operator()(std::int_fast32_t d) override {
        if (character_context->is_black()) {
            character_context->bitmap.add_blackline(character_context->m, character_context->n, d);
        }
        character_context->m += d;
        character_context->toggle_color();
    }

};

class get1byte : public Argument {
public:
    using Argument::Argument;

    int_fast32_t operator()() override {
        return file_context->read1();
    }
};

我可以明确地调用这些,例如,

paint _paint (characterContext);
get1byte _1byte (fileContext);

_paint(_1byte());

(或者这至少可以编译)。

但是我有

std::array<std::function<void()>, 256> opcodes;
opcodes[64] = [_paint, _1byte](){ _paint(_1byte()); };

编译器抱怨,

No matching function for call to object of type 'const get1byte'

如何让它按预期工作?我宁愿避免修改OpCode operator() 签名以采用Argument,因为在某些情况下,我想在参数中放入一个具有常量值的lambda,例如_paint

【问题讨论】:

  • 在 lambda 中捕获的对象是 const,除非 lambda 被标记为 mutable。你的operator() 没有被标记为const,所以它们不能被const 对象调用。另外,请注意您的 lambda 正在捕获 按值 的对象,因此它正在对它们的 副本 进行操作,这是您真正想要的吗?如果不是,请改为通过引用捕获对象。
  • 如果底层对象消失,您也会遇到问题。如果您要存储这些操作码以供以后查找,那么您需要在使用 lambda 之前确保 _paint 和 _1byte 没有被破坏。
  • 在 lambda 中按值捕获的对象是 const,除非 lambda 被标记为 mutablegodbolt.org/z/51dc5d
  • @RemyLebeau 我标记方法const 还是它的参数?我想我确实想要副本。仿函数通常只有一个 shared_ptr 作为它们的内容,我在构造函数中初始化它们。 (现在我认为这可能是一个问题)。我怀疑 C++ 的人会看着我的代码库并摇头并喃喃地说,“Java 程序员”对我的代码。
  • @DonHosek 您必须将operator() 本身标记为const,例如:void operator()(std::int_fast32_t d) const override ... int_fast32_t operator()() const override,这意味着基类operator() 必须是@987654344 @ 以及因为您使用的是override。如果这不是一个选项,请在 lambda 上使用 mutable[_paint, _1byte]() mutable { _paint(_1byte()); };

标签: c++ lambda functor


【解决方案1】:

在 Remy Lebeau 的指导下,我已经弄清楚我需要做什么:我必须在我的运算符函数的声明中添加 const,例如,

int_fast32_t operator()() const override {
    return file_context->read1();
}

Argument 实现中,抽象基类将方法定义为

virtual std::int_fast32_t operator()() const = 0;

然后我可以将我的作业写成,例如,

opcodes[64] = [=](){ _paint(_1byte()); };

一切都很好(或者至少不会产生编译器错误——我们会在我完成代码更新后看到)。我什至设法使用std::generate 改进了另一段代码,让 lambda 成为 lambda:

std::generate_n(opcodes.begin(), 64, [&index, _paint](){ auto rv = [=](){_paint(index);  }; ++index; return rv; });

如果运气好的话,一切都会好起来的(尽管我在填充的后面有一个类似的构造发生,我可能会将 lambda 重构为一个函数)。

【讨论】:

    猜你喜欢
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    相关资源
    最近更新 更多