21 votos

Variadic plantilla como parámetro de plantilla: deducción trabaja con GCC, pero no con Clang

Al compilar C++11 código con tanto GCC 4.7.2 y Clang 3.1, me encontré con un problema con el Sonido metálico de en la gestión de deducir un argumento de plantilla donde GCC tiene éxito. En una más, de forma abstracta, el código es este:

src/test.cc:

struct Element {
};

template <typename T>
struct FirstContainer {
};

template <typename T, typename U = Element>
struct SecondContainer {
};

template <template <typename> class Container>
void processOrdinary(Container<Element> /*elements*/) {
}

template <template <typename, typename> class Container>
void processOrdinary(Container<Element, Element> /*elements*/) {
}

template <template <typename, typename...> class Container>
void processVariadic(Container<Element> /*elements*/) {
}

int main() {
  // This function instantiation works in both GCC and Clang.
  processOrdinary(FirstContainer<Element>{});
  // This function instantiation works in both GCC and Clang.
  processOrdinary(SecondContainer<Element>{});
  // This function instantiation works in both GCC and Clang.
  processVariadic(FirstContainer<Element>{});
  // This function instantiation works in both GCC and Clang.
  processVariadic<SecondContainer>(SecondContainer<Element>{});
  // This function instantiation works in GCC but not in Clang.
  processVariadic(SecondContainer<Element>{});
  return 0;
}

De la lectura de los ejemplos en el §14.3.3 y las especificaciones en el §14.8.2 de la norma, creo que la deducción de trabajo, pero no puedo decir seguro. Este es el resultado que obtengo de la construcción:

mkdir -p build-gcc/
g++ -std=c++0x -W -Wall -Wextra -Weffc++ -pedantic -c -o build-gcc/test.o src/test.cc
g++  -o build-gcc/test build-gcc/test.o
mkdir -p build-clang/
clang++ -std=c++11 -Weverything -Wno-c++98-compat -c -o build-clang/test.o src/test.cc
src/test.cc:34:3: error: no matching function for call to 'processVariadic'
  processVariadic(SecondContainer<Element>{});
  ^~~~~~~~~~~~~~~
src/test.cc:21:6: note: candidate template ignored: failed template argument deduction
void processVariadic(Container<Element> /*elements*/) {
     ^
1 error generated.
make: *** [build-clang/test.o] Fel 1

¿Por qué los resultados son diferentes? Es GCC descuidado, Sonar tonto, ¿mi código de contener comportamientos no especificados o en todos?

7voto

Richard Smith Puntos 3935

Clang está tratando de deducir los argumentos para esta convocatoria:

processVariadic(SecondContainer<Element>{});

Desde SecondContainer tiene una plantilla predeterminada argumento, esto es equivalente a:

processVariadic(SecondContainer<Element, Element>{});

Así, se lleva argumento de plantilla de la deducción con P = Container<Element> y A = SecondContainer<Element, Element>. Se puede de inmediato deducir que el Container de la plantilla es el parámetro de SecondContainer.

Siguiente, se considera que los argumentos de plantilla. Dado que el tipo de argumento está totalmente resuelto, Clang cree que el parámetro debe haber tantos tipos, o deducción no puede tener éxito (no toma argumentos predeterminados en cuenta). Por lo que las banderas de una deducción fracaso.


Así que, ¿qué debería suceder? En las palabras de [temp.deduct.type]p8,

Una plantilla de tipo de argumento T, una plantilla plantilla argumento TT o una plantilla de no-tipo de argumento que puede deducir si P y A tienen una de las siguientes formas:
[...]
TT<T>
TT<i>
TT<>
donde [...] <T> representa argumento de plantilla de listas en las que al menos un argumento contiene un T, <i> representa argumento de plantilla de listas en las que al menos un argumento contiene un i y <> representa a la plantilla de las listas de argumentos donde no hay argumento que contiene un T o i.

En el fin de coincidir con los argumentos de plantilla, nos dirigimos a [temp.deduct.type]p9:

Si P tiene un formulario que contiene <T> o <i>, entonces cada argumento Pi de la respectiva plantilla de lista de argumentos P es en comparación con el correspondiente argumento Ai de la plantilla correspondiente lista de argumentos de A.

Hay dos cosas que observar aquí. Una de ellas es que esta regla no dice qué pasa si la lista Pi y Ai tienen longitudes diferentes (como lo son en este caso), y la interpretación común es que parece ser que los que no coinciden los elementos no son examinados. La otra es que esta regla no debe ser seguido de todos modos, ya que la forma de P no contiene <T> o <i> (sólo contiene <>, debido a que no existen parámetros de la plantilla).


Así, Clang se equivocó al rechazar este código. Me he fijado en r169475.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X