Search code examples
c++lambdafunctor

Using functor in lambda


I'm getting hung up on some syntax for working with functors and lambdas in C++.

I define functors as:

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();
    }
};

I can call these explicitly by doing, e.g.,

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

_paint(_1byte());

(or this at least compiles).

But then I have

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

which has the compiler complaining,

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

How do I get this to work as expected? I'd prefer to avoid modifying the OpCode operator() signature to take Argument since in some instances I'd like to put a lambda in with a constant value in the argument to, e.g., _paint.


Solution

  • Thanks to Remy Lebeau's directions, I have managed to figure out what I needed to do: I had to add const to the declarations of my operator functions, e.g.,

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

    in an Argument implementation, with the abstract base class defining the method as

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

    Then I was able to write my assignments as, e.g.,

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

    and all was well (or at least doesn't generate compiler errors—we'll see once I've finished updating my code). I've even managed to improve another piece of code using std::generate to have a lambda make a lambda:

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

    and with any luck, all will be well (although since I have a similar construction happening later in the fill, I'll likely refactor the lambda as a function).