practices guidelines best c++ templates language-lawyer c++17

guidelines - c++ best practices



¿Son intercambiables los tipos de marcadores de tipo no tipo de plantilla en el caso de un parámetro de plantilla de plantilla? (1)

Considere un ejemplo simple:

int x; template <template <auto> class TT> struct Foo { void foo() { TT<(x)> tt; static_cast<void>(tt); } }; template <decltype(auto)> struct Bar { }; int main() { Foo<Bar> foobar; foobar.foo(); }

[clang] parece lidiar con la idea de decltype(auto) placeholder a pesar del uso de auto en la plantilla de declaración de parámetros de la plantilla sin ningún problema.

[gcc] por otro lado - no muy bien:

prog.cc:6:13: error: el valor de ''x'' no se puede utilizar en una expresión constante

Como de costumbre, ¿qué comportamiento se espera según el estándar? ¿O tal vez todo es posible y el código está mal formado (esta vez supongo que no, pero no puedo descartarlo definitivamente)?

PD. Lo siento por romper uno de los compiladores de nuevo;)


La respuesta original aquí tenía a Foo<Bar> mal formado, en realidad ahora creo que está bien formado. Pero en última instancia, clang bug se basa.

De hecho, creo que incluso Foo<Bar> está mal formado. Las nuevas reglas que siguen a P0522 son las siguientes:

Un argumento de plantilla coincide con un parámetro de plantilla de plantilla P cuando P es al menos tan especializado como el argumento de plantilla A

dónde:

Una plantilla plantilla-parámetro P es al menos tan especializada como una plantilla plantilla-argumento A si, dada la siguiente reescritura a dos plantillas de función, la plantilla de función correspondiente a P es al menos tan especializada como la plantilla de función correspondiente a A acuerdo con el reglas de ordenamiento parcial para las plantillas de función ([temp.func.order]). Dada una plantilla de clase inventada X con la lista de parámetros de plantilla de A (incluidos los argumentos predeterminados):

  • Cada una de las dos plantillas de función tiene los mismos parámetros de plantilla, respectivamente, como P o A
  • Cada plantilla de función tiene un único parámetro de función cuyo tipo es una especialización de X con argumentos de plantilla correspondientes a los parámetros de plantilla de la plantilla de función respectiva donde, para cada parámetro de plantilla PP en la lista de parámetros de plantilla de la plantilla de función, un argumento de plantilla correspondiente AA se forma Si PP declara un paquete de parámetros, entonces AA es la expansión del paquete PP... ([temp.variadic]); De lo contrario, AA es la expresión-expresión PP .

Si la reescritura produce un tipo no válido, P no es tan especializado como A

Lo que significa que para verificar si Foo<Bar> sí está bien, sintetizamos:

template <decltype(auto) I> struct X; template <auto I> void __f(X<I> ); // P template <decltype(auto) I> void __f(X<I> ); // A

Todos los tipos aquí son válidos (por lo que la última declaración no se aplica). Ahora, por lo general, cuando hacemos pedidos parciales, es en el contexto de una resolución de sobrecarga o elegir una especialización de plantilla de clase, en cuyo caso lo que buscamos es la plantilla de función "más especializada" , donde F es más especializada que G si F es al menos tan especializado como G y G no es al menos tan especializado como F

Pero en este contexto, no nos importa lo que está más especializado. Solo necesitamos que P sea ​​al menos tan especializado como A Todo lo que significa que la deducción tiene que ser exitosa de A a P Entonces, si sintetizamos algún tipo único U con algún valor V , ¿podemos deducir X<I> de X<V> ? Sí. Por lo tanto, P es al menos tan especializado como A , por lo que la Bar argumentos y plantillas coincide con el parámetro TT plantillas.

Ahora, pasando ese punto, diría que esto es un error. La plantilla plantilla-parámetro es template <auto> , que es lo que deberíamos usar para validar la expresión. Con un parámetro de plantilla no tipo auto , intentaríamos usar x como un valor, pero x no es una expresión constante válida, por lo que esto debería fallar. clang parece estar usando la template <decltype(auto) > directamente, lo cual no estoy seguro de que sea válido.

Dicho esto, no estoy seguro de que este caso haya sido considerado, no veo ninguna redacción de ninguna manera y vale la pena plantear un problema.