c++ c++11 language-lawyer variadic-templates template-aliases

c++ - Paquete de expansión para la plantilla de alias



c++11 language-lawyer (1)

Parece que un argumento de paquete solo se puede expandir en lugar de un parámetro de paquete de una plantilla de alias. Esto no es cierto para una clase o una plantilla de función:

template <class T, class... Args> struct x { using type = T; }; template <class T, class... Args> using x_t = typename x<T, Args...>::type; template <class... Args> using x_fix_t = typename x<Args...>::type; template <class... Args> auto f(Args...) -> void { typename x<Args...>::type v1; // OK x_t<Args...> v2; // Error x_fix_t<Args...> v3; // OK }

caso más simple:

template <class T, class U> using y_t = T; template <class... Args> auto f(Args...) -> void { y_t<Args...> v4; // Error }

El código anterior genera un error (incluso si f nunca se crea una instancia) con c++11 y c++14 en g++ 4.9 , g++ 5.1 y clang 3.5 .

¿Por qué esto no está permitido y cuál es la regla general? No veo ninguna razón para restringir esto. Parece una prohibición muy extraña.

En cuanto a por qué no escribir como x_fix_t con la primera variante, es más claro que x_t tiene un primer argumento obligatorio. (por ejemplo, esa es la razón por la que f() no está permitido). Pero esto no es tan importante, la solución es fácil. La pregunta permanece: ¿Por qué?

error de gcc:

error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T, class ... Args> using x_t = typename x::type’

error de clang:

error: pack expansion used as argument for non-pack parameter of alias template x_t<Args...> v2;


Esto compila en GCC 4.8 pero falla en GCC 4.9, que es evidencia de que está relacionado con DR1430 y el informe de errores # 59498 . La solución propuesta por Roy Chrihfield es exactamente la misma que la tuya:

Rewriting the code to use a struct succeeds: template <typename T, typename ...> struct alias { using type = T; }; template <typename ...T> using variadic_alias = typename alias<T...>::type;

Además, Jason Merrill explica por qué debería fallar:

En realidad, no, esto es en gran medida un problema Core 1430; no hay forma de manipular variadic_alias sin mencionar el nombre de una plantilla de alias en el proceso y se supone que son completamente transparentes. Esto solo funciona en 4.8 por accidente porque la verificación está deshabilitada para el lanzamiento.

No hay más discusión en el informe de errores, por lo que podemos pasar a DR1430:

Originalmente, la expansión de un paquete no podía expandirse a una lista de parámetros de plantilla de longitud fija, pero esto se modificó en N2555. Esto funciona bien para la mayoría de las plantillas, pero causa problemas con las plantillas de alias.

En la mayoría de los casos, una plantilla de alias es transparente; cuando se usa en una plantilla, podemos sustituirla en los argumentos de la plantilla dependiente. Pero esto no funciona si el ID de plantilla usa una expansión de paquete para parámetros no variados. Por ejemplo:

template<class T, class U, class V> struct S {}; template<class T, class V> using A = S<T, int, V>; template<class... Ts> void foo(A<Ts...>);

No hay forma de expresar A en términos de S, por lo que debemos mantener la A hasta que tengamos que sustituir los Ts, y por lo tanto debe manejarse en el proceso.

Actualmente, EDG y Clang rechazan este caso de prueba, quejándose de muy pocos argumentos de plantilla para A. G ++ también, pero pensé que era un error. Sin embargo, en la lista de ABI, John Spicer argumentó que debería ser rechazada.

(Véase también el número 1558.)

Notas de la reunión de octubre de 2012:

El consenso de CWG fue que este uso debería prohibirse, impidiendo el uso de una plantilla de alias cuando un argumento dependiente no puede ser simplemente sustituido directamente en el ID de tipo.

Nota adicional, abril de 2013:

Para otro ejemplo, considere:

template<class... x> class list{}; template<class a, class... b> using tail=list<b...>; template <class...T> void f(tail<T...>); int main() { f<int,int>({}); }

Hay una variación en la implementación en el manejo de este ejemplo.

En otras palabras, este es un tema en curso sin resolución (AFAIC) a la vista.