c++ lambda language-lawyer standards final

c++ - ¿La heredabilidad de las lambdas está garantizada por la norma?



language-lawyer standards (2)

El efecto de final se especifica en [class]/3 :

Si una clase está marcada con el final class-virt-specifier y aparece como una clase o tipo de declive en una cláusula base , el programa está mal formado.

Es decir, no importa si la clase es final. Solo importa si la clase está marcada con el especificador final . Dado que un tipo de cierre no tiene ninguna declaración en el archivo fuente, es imposible marcarlo como final , y por lo tanto [class] / 3 no se aplica.

En el estándar de C ++, los tipos de cierre se definen de la siguiente manera:

[expr.prim.lambda.closure] El tipo de una expresión lambda (que también es el tipo del objeto de cierre) es un tipo de clase sin unión único, sin nombre, llamado tipo de cierre , cuyas propiedades se describen a continuación. [...]

El estándar no parece definir si el tipo de clase sin unión sin nombre es definitivo o no. ¿Un compilador que implementa lambdas como clases finales cumplirá con el estándar, o tenemos la garantía de que uno puede heredar de lambdas?

La pregunta no es si es útil o no heredar de las lambdas: es un hecho que es útil. La pregunta es si la norma proporciona esta garantía.


Sí, el tipo de cierre no debe ser definitivo. Al menos esa es mi interpretación.

§8.1.5.1 Tipos de cierre [expr.prim.lambda.closure]

Una implementación puede definir el tipo de cierre de manera diferente a lo que se describe a continuación, siempre que esto no altere el comportamiento observable del programa, sino cambiando:

  • ... [no se aplica]

El estándar entonces no describe el tipo de cierre como definitivo. Hacerlo definitivo alteraría el comportamiento observable y el tipo de cierre no debe ser definitivo.

Respecto al comportamiento observable. Considera esto:

auto l = []{}; return std::is_final_v<decltype(l)>;

Hacer que el tipo de cierre sea final modificaría claramente el comportamiento observable de un programa válido.

En cuanto a un caso de uso, en realidad puede ser una característica muy útil:

template <class... Fs> struct Overload : Fs ... { using Fs::operator()...; }; template <class... Fs> Overload(Fs...) -> Overload<Fs...>; auto test() { Overload f = {[] (int a) { return a * 100; }, [] (int a, int b) { return a + b;}}; return f(1) + f(2, 3); // 105 }

godbolt en acción en godbolt

Gracias a hvd y rakete1111 por las discusiones y comentarios en los comentarios.