Почему моя функция 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.

20

Решение

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

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

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

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

10

Другие решения

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

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

Это говорит:

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

Какие списки под ним:

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

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

7

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

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

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

5
А ты уже прошел курс программирования? Супер скидка!
Прокачать скилл $$$
×