Статический массив лямбда-функций (С++)

Я хотел бы сделать что-то вроде этого (внутри класса):

static constexpr MyStruct ops[6] = {
    {'+', [&] (double a, double b) { return a+b; } },
    {'-', [&] (double a, double b) { return a-b; } },
    ...
};

Где MyStruct определяется как:

typedef double (*binOp)(double, double);
struct MyStruct {
    char c;
    binOp fn;
};

Я также пробовал:

std::function <double(double,double)> fn;

для определения fn, но не повезло.

Ошибка, которую я получаю для первого случая, это "ошибка: инициализатор поля не является константой", которую я действительно не получаю. Если я попытаюсь с std::function, это ухудшится, так как он говорит: "не может быть инициализирован непостоянным выражением при объявлении".

Почему лямбда-функция непостоянна? Я что-то пропустил?

Ответ 1

Когда вы создаете объект constexpr, все, что вы передаете в него, должно быть основным константным выражением, [decl.constexpr]/9:

A constexpr спецификатор, используемый в объявлении объекта, объявляет объект как const. Такой объект должен иметь буквальный тип и должен быть инициализирован. Если он инициализируется вызовом конструктора, , то вызов должен быть постоянным выражением (5.19).

и, из [expr.const] lambdas не являются постоянными выражениями 1:

Условное выражение e является выражением постоянной константы, если оценка e, следуя правилам абстрактная машина (1.9), оценила бы одно из следующих выражений:

  • [...]
  • лямбда-выражение (5.1.2);
  • [...]

Однако это относится только к constexpr, а не к const, поэтому вы можете просто сделать это:

static const MyStruct ops[6] = {
    {'+', [] (double a, double b) { return a+b; } },
    {'-', [] (double a, double b) { return a-b; } },
};

Примечание: вашим лямбдам не нужно ничего захватывать, поэтому вам нужно просто пустой список захвата [].


1 Как указано dyp, есть предложение изменить это: N4487

Ответ 2

захват лямбда не может разлагаться на указатель функции.

и оператор для возврата указателя функции из (не захватывающей) лямбда не constexpr.