Hoy estaba leyendo la página de soporte de C ++ 17 de clang. Noté algo extraño. La función Hacer coincidir los parámetros de la plantilla con los argumentos compatibles (P0522R0) está marcado como parcial, ya que debe activarse mediante un interruptor. Su nota dice:

A pesar de ser la resolución de un Informe de defectos, esta función está deshabilitada de forma predeterminada en todas las versiones de idiomas y se puede habilitar explícitamente con la marca -frelaxed-template-template-args en Clang 4. El cambio al estándar carece de un cambio correspondiente para la ordenación parcial de la plantilla, lo que da como resultado errores de ambigüedad para el código razonable y previamente válido. Se espera que este problema se solucione pronto.

¿Qué tipo de construcciones se rompe cuando se activa esta función? ¿Por qué puede romper el código y cómo?

19
Guillaume Racicot 14 nov. 2017 a las 21:48

2 respuestas

La mejor respuesta

Puedes tener un código como este:

template<template<typename> typename>
struct Foo {};

template<typename, typename = void>
struct Bar {};

Foo<Bar> unused;

Sin la resolución del defecto, unused estaría mal formado, porque foo toma una plantilla con solo un parámetro de plantilla, y no dos. Si confió en esto (tal vez para SFINAE):

template<template<typename> typename>
void foo();

template<template<typename, typename> typename>
void foo();

template<typename, typename = void>
struct Bar {};

int main() {
    foo<Bar>(); // ambiguous after resolution!
}

¡Entonces la llamada fallaría! El problema es que no hubo un cambio correspondiente en el orden parcial, por lo que ambas funciones candidatas tienen la misma viabilidad y la llamada es ambigua.

14
Rakete1111 25 ene. 2018 a las 16:21

Un escenario más común es cuando algún código quiere inspeccionar los argumentos de la plantilla con un conjunto de especializaciones parciales, por ejemplo:

template<class> struct Foo;

template<template<class> class X, class T> 
struct Foo<X<T>> { /* ... */ };

template<template<class, class> class X, class T, class U> 
struct Foo<X<T, U>> { /* ... */ };

// etc., etc.

Foo<std::vector<int>> ahora está mal formado sin una corrección de pedido parcial adecuada.

6
T.C. 18 ene. 2018 a las 21:28