El código simple como el siguiente o Godbolt tiene resultados diferentes de gcc, clang y Visual Studio.
auto foo1(int n) -> decltype(([n]() { return n+1; }())) // gcc error: use of parameter outside function body before '+' token { return [n]() { return n+1; }(); } auto foo2(int n) -> decltype(([&n]() { return n+1; }())) // gcc error: use of parameter outside function body before '+' token { return [&n]() { return n+1; }(); } auto foo3(int n) -> decltype(([&]() { return n+1; }())) // gcc error: use of parameter outside function body before '+' token // gcc and clang error: non-local lambda expression cannot have a capture-default // VS2022 17.1 warning C5253: a non-local lambda cannot have a capture default { return [&]() { return n+1; }(); }Parece que gcc no permite ningún tipo de captura si la lambda está en función de tipo de retorno final (o noexcept(noexcept(...))). clang está bien con la captura por valor y la captura por referencia, pero no está bien con la captura predeterminada. Visual Studio hasta 17.0 permite cualquier tipo de captura. Visual Studio 17.1 da una advertencia para la captura predeterminada.
¿Cuál es el comportamiento correcto aquí? Parece que gcc, clang y el último VS 17.1 están de acuerdo en que la captura predeterminada no está permitida en el tipo de retorno final (o noexcept(noexcept(...))). ¿Pero es un diseño correcto? Es muy conveniente poner la misma expresión en la declaración de retorno, noexcept y el tipo de retorno final (a menudo por una macro) si la función es de una sola línea. Pero ahora no es posible si hay una lambda con captura (¿predeterminada?) en esta expresión.
De [expr.prim.lambda.capture]/3 :
Una expresión lambda no debe tener una captura predeterminada o una captura simple en su introductor lambda, a menos que su ámbito de inclusión más interno sea un ámbito de bloque ( [basic.scope.block] ) o aparezca dentro de un inicializador de miembro predeterminado y su ámbito de inclusión más interno scope es el ámbito de la clase correspondiente ( [basic.scope.class] ).
Lo que significa que las capturas como [n] , [&n] o [&] no están permitidas en los tipos de devolución finales o los especificadores noexcept , pero las capturas inicializadas como [i = 1] sí.
Entonces, GCC tiene razón al rechazar las dos primeras definiciones de función y GCC y Clang tienen razón al rechazar la última.