Подтвердить что ты не робот

Почему моя функция constexpr не возвращает лямбда?

Я обнаружил, что этот фрагмент кода не работает:

typedef int (*fp)(int a, int b);

constexpr fp addition()
{
    return [](int a, int b){ return a+b; };
}

#include <iostream>

int main()
{
    fp fun = addition();
    std::cout << fun(2,2);
}

Это дает мне ошибку

cexpr.cpp: In function 'constexpr int (* addition())(int, int)':
cexpr.cpp:5:43: error: call to non-constexpr function 'addition()::<lambda(int,
int)>::operator int (*)(int, int)() const'

Почему? Я не называю это здесь.

Работа с прямым подходом:

typedef int (*fp)(int a, int b);

#include <iostream>

int main()
{
    fp fun = [](int a, int b){ return a+b; };
    std::cout << fun(2,2);
}

Я использую MinGW с g++ версии 4.7.2.

4b9b3361

Ответ 1

Ваша функция fp() не возвращает тип литерала, поэтому она не может быть функцией constexpr:

Из раздела 7.1.5: "Определение функции constexpr должно удовлетворять следующим ограничениям:

  • он не должен быть виртуальным (10.3);
  • его тип возврата должен быть литеральным типом;
  • каждый из его типов параметров должен быть литеральным типом;
  • его тело функции должно быть = delete, = default, или составной оператор, содержащий только
    • null,
    • static_assert-декларация
    • объявления typedef и псевдонимы-объявления, которые не определяют классы или перечисления,
    • с использованием деклараций,
    • с использованием Директив,
    • и ровно один оператор return;"

Я не думаю, что здесь есть какая-то ошибка, и особенно ничего не связано с лямбдами, как упоминалось в более раннем ответе: переменные просто не могут быть объявлены внутри функции constexpr.

Ответ 2

Согласно N3376 рабочий проект стандартного раздела 5.19 [expr.const]:

В некоторых контекстах требуются выражения, которые удовлетворяют дополнительным требования, подробно описанные в этом подпункте; другие контексты различная семантика в зависимости от того, удовлетворяет ли выражение эти требования. Выражения, удовлетворяющие этим требованиям, называемых постоянными выражениями. [Примечание: константные выражения могут быть оценивается во время перевода. - примечание к концу]

Далее говорится:

Условное выражение является выражением постоянной константы, если оно включает одно из следующего в качестве потенциально оцениваемого подвыражения (3.2), но подвыражения логического И (5.14), логического ИЛИ (5.15), и условные (5.16) операции, которые не оцениваются, не являются рассмотрено [Примечание: перегруженный оператор вызывает функцию.- end примечание]:

Что перечисляет под ним:

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

Поэтому, хотя я не знаю достаточно стандартного, я считаю, что это говорит о том, что constexpr не должен иметь внутри себя лямбда-выражения.

Ответ 3

Сообщение об ошибке gcc дало вам точное и правильное:

error: вызов функции non-constexpr 'add()::
              < лямбда (целое, целое) > ::
                оператор int (*) (int, int)() const

Я немного переформатировал и добавил акцент. Принуждая лямбда к указателю на функцию, вы неявно вызываете автоматически созданную функцию преобразования от лямбда до pointer to function of type "auto (int, int)->int", которая не является функцией constexpr, потому что автоматически созданная функция преобразования не объявляется constexpr (и стандартная не требует, чтобы это было).