После этого ответа Теперь мне интересно, каковы правила для времени жизни лямбда-выражения и как они соотносятся со временем жизни указателей на функции, которые создаются автоматическим преобразованием.Есть несколько вопросов о времени жизни лямбд (например, здесь и здесь ), и в этом случае ответы «они ведут себя точно так же, как вы сами написали полный объект функтора», однако ниобратимся к преобразованию в указатель на функцию, что вполне разумно может быть особым случаем.
Я собрал небольшой рабочий пример, иллюстрирующий мое беспокойство:
#include <iostream>
typedef int (*func_t)(int);
// first case
func_t retFun1() {
static auto lambda = [](int) { return 1; };
// automatically converted to func_t
return lambda;
}
// second case
func_t retFun2() {
// no static
auto lambda = [](int) { return 2; };
// automatically converted to func_t and
// the local variable lambda reaches the end of its life
return lambda;
}
int main() {
const int a = retFun1()(0);
const int b = retFun2()(0);
std::cout << a << "," << b << std::endl;
return 0;
}
Хорошо ли это определено для обоих случаев?Или только для retFun1()
?Вопрос заключается в том, «является ли та функция, на которую указывает указатель функции, необходимой для вызова самого объекта функтора или для переопределения тела в отдельной функции?»Любой из них может иметь смысл, но тот факт, что преобразование в указатель на функцию, в частности, требует лямбда без захвата, наводит на мысль, что на самом деле это может быть последний.
Другими словами, я вижу по крайней мере дваразумным образом компилятор может захотеть реализовать такие лямбды.Одна из возможных, легальных реализаций может состоять в том, что компилятор может синтезировать код, подобный:
func_t retFun3() {
struct __voodoo_magic_lambda_implementation {
int operator()(int) const {
return 3;
}
static int plainfunction(int) {
return 3;
}
operator func_t() const {
return plainfunction;
}
} lambda;
return lambda;
}
, в этом случае подойдут как static
, так и не static
варианты retFun
.Однако, если для компилятора также допустимо реализовывать лямбда-выражения, например:
static int __voodoo_impl_function(int x);
static struct __voodoo_maigc_impl2 {
int operator()(int) const {
return 4;
}
operator func_t() const {
return __voodoo_impl_function;
}
} *__magic_functor_ptr;
static int __voodoo_impl_function(int x) {
return (*__magic_functor_ptr)(x);
}
func_t retFun4() {
__voodoo_maigc_impl2 lambda;
// non-static, local lifetime
__magic_functor_ptr = λ //Or do the equivalent of this in the ctor
return lambda;
}
, тогда retFun2()
- неопределенное поведение.