empo de vida de objetos lambda em relação à conversão de ponteiro de funç

Segueesta resposta Agora estou imaginando quais são as regras para a vida útil das lambdas e como elas se relacionam com a vida útil dos ponteiros de função criados pela conversão automática. Existem várias perguntas sobre a vida útil das lambdas (por exemplo,aqu eaqu), caso em que as respostas são "elas se comportam exatamente como você escreveu o objeto functor completo", no entanto, nenhuma delas aborda a conversão em ponteiro de função, o que pode ser sensivelmente um caso especia

Eu montei este pequeno exemplo de trabalho que ilustra minha preocupação:

#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;
}

Isso está bem definido para os dois casos? Ou apenas pararetFun1()? A questão é: "é a função que o ponteiro da função aponta para chamar o próprio objeto functor ou reimplementar o corpo em uma função separada?" Qualquer um deles faria sentido, mas o fato de a conversão em ponteiro de função exigir especificamente um lambda sem captura sugere que ele pode realmente ser o últim

Colocar outra maneira - eu posso ver pelo menos duas maneiras sensatas de um compilador querer implementar essas lambdas. Uma possível implementação legal pode ser para um compilador sintetizar código como:

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

nesse caso, ambos osstatic e nãostatic variantes deretFun seria ótimo. Se, no entanto, também é legal para um compilador implementar o lambda como:

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 = &lambda; //Or do the equivalent of this in the ctor
  return lambda;
}

entãoretFun2() é um comportamento indefinido.

questionAnswers(1)

yourAnswerToTheQuestion