c++ templates lambda c++1z non-type

c++ - ¿Por qué está fallando gcc cuando se usa lambda para un parámetro de plantilla sin tipo?



templates c++1z (2)

De acuerdo con http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter , parece que el enlace externo ya no es un requisito desde C ++ 17. El mismo lenguaje se encuentra en el borrador de C ++ 17 bajo [temp.arg.nontype] en http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf (nota que está incorrectamente vinculado como un borrador de C ++ 14).

El argumento de plantilla que se puede usar con un parámetro de plantilla sin tipo puede ser cualquier expresión constante convertida del tipo del parámetro de plantilla ...

Las únicas excepciones son que los parámetros de plantilla de tipo no de referencia y el tipo de puntero no pueden referirse a / ser la dirección de

  • un subobjeto (incluido un miembro de clase no estático, un subobjeto base o un elemento de matriz);
  • un objeto temporal (incluido uno creado durante la inicialización de referencia);
  • un literal de cadena;
  • el resultado de typeid;
  • o la variable predefinida __func__.

Ese enlace en cppreference también menciona específicamente los punteros de función, pre C ++ 17:

Las siguientes limitaciones se aplican al crear instancias de plantillas que tienen parámetros de plantilla sin tipo:

...

Para los punteros a las funciones, los argumentos válidos son punteros a las funciones con vinculación (o expresiones constantes que evalúan a valores de puntero nulos).

Debido a que su pregunta está etiquetada como C ++ 1z (probablemente deberíamos tener una etiqueta de 17 ahora y usarla en vez de que 17 haya terminado) deberíamos usar el primer conjunto de reglas. Su ejemplo no parece caer en ninguna de las categorías de excepción para C ++ 17, y por lo tanto, gcc está en error.

Tenga en cuenta que clang no compila su ejemplo si cambia el indicador de idioma a 14.

El siguiente fragmento se compila sin error con Clang 4.0, pero GCC 7.0 produce errores (observe el uso del indicador -std = c ++ 1z).

using FuncT = int (*)(double); template <FuncT FUNC> int temp_foo(double a) { return FUNC(a); } int foo(double a) { return 42; } void func() { auto lambda = [](double a) { return 5; }; struct MyStruct { static int foo(double a) { return 42; } }; temp_foo<foo>(3); temp_foo<static_cast<FuncT>(lambda)>(3); temp_foo<MyStruct::foo>(3); }

Específicamente, GCC se queja de que tanto el método lambda como el de la clase anidada no tienen vinculación, por lo que no se pueden usar como un argumento de plantilla sin tipo.

Al menos para el caso lambda creo que Clang es correcto (y GCC está equivocado) desde (citando de cppreference , el operador de conversión):

El valor devuelto por esta función de conversión es un puntero a una función con enlace de lenguaje C ++ que, cuando se invoca, tiene el mismo efecto que invocar directamente al operador de llamada de función del objeto de cierre.

¿Se está portando mal GCC?


Estoy de acuerdo con la respuesta de Nir y quería agregarle algo de información. Cita la sección relevante en el estándar (§14.3.2 [temp.arg.nontype]) que muestra que ya no es necesario que los parámetros que no son de tipo tengan un enlace, pero eso aún no muestra que GCC se está portando mal para la parte lambda Para eso tenemos que mostrar que static_cast<FUNCT>(lambda) es una expresión constante convertida. Para eso necesitamos un borrador más nuevo del que Nir vinculó. Y esta sección

§5.1.5 Expresiones de Lambda [expr.prim.lambda]:

  1. El tipo de cierre para una expresión lambda no genérica sin captura lambda tiene una función de conversión a puntero para funcionar con enlace de lenguaje C ++ (7.5) que tiene el mismo parámetro y tipos de retorno que el operador de llamada a función del tipo de cierre. [...] La función de conversión es pública, constexpr, no virtual, no explícita, const y tiene una especificación de excepción que no arroja.

Curiosamente, GCC afirma haber implementado esto ( N4268 ) en la versión 6 ya lanzada (en caso de que quiera excusar el comportamiento de GCC diciendo que GCC 7 aún no se ha lanzado oficialmente, así que tal vez cuando salga esto lo haga). ser reparado):

Language Feature Proposal Available in GCC? SD-6 Feature Test Allow constant evaluation for all non-type template arguments N4268 6 __cpp_nontype_template_args >= 201411

Entonces, en resumen, esto es un error en GCC.