c++ - installed - clang windows
C++ inconsistencia entre gcc y clang (1)
Encontré una inconsistencia en C ++ entre gcc
(versiones 4.8.1
, 4.8.2
) y clang
(versiones 3.3
, 3.4
). Me pregunto cuál es la correcta. Aquí está el programa:
template < typename T > struct Result {};
template < typename T > struct Empty {};
template < typename T >
struct Bad_Type_Fcn {
typedef typename Empty< T >::type type;
};
template < typename T >
Result< T >
f( const T& ) {
return Result< T >();
}
template< class U >
Result< typename Bad_Type_Fcn< U >::type >
f( const U&, int ) {
return Result< typename Bad_Type_Fcn< U >::type >();
}
int main() {
(void)f< int >(42);
}
Claramente, este código no pretende hacer nada; es una simplificación agresiva de algo que aparece en la biblioteca de Boost Range (con f
simplificando make_iterator_range
). Bad_Type_Fcn
es una función de tipo (técnicamente, una struct
) que nunca debe ser instanciada, porque el tipo Empty<T>::type
nunca existe, para cualquier T
La presencia de esta struct
y de la especialización de la segunda plantilla de f()
no es un error en sí mismo. IRL, f()
proporciona alguna funcionalidad para ciertos tipos para los cuales Bad_Type_Fcn
no está vacío. Sin embargo, esa no es la preocupación aquí, razón por la cual simplifiqué eso. Todavía quiero que f()
funcione para tipos donde Bad_Type_Fcn
está vacío.
Estoy compilando con {g++|clang++} [-std=c++0x] -pedantic -Wall -Wextra -c
. La selección estándar de idioma no parece hacer una diferencia. Con clang
, el programa compila sin errores ni advertencias. Con gcc
, me sale un error:
weird.cpp: In instantiation of ‘struct Bad_Type_Fcn<int>’:
weird.cpp:17:5: required by substitution of ‘template<class U> Result<typename Bad_Type_Fcn<T>::type> f(const U&, int) [with U = int]’
weird.cpp:22:26: required from here
weird.cpp:6:43: error: no type named ‘type’ in ‘struct Empty<int>’
typedef typename Empty< T >::type type;
Lo que parece estar sucediendo es que clang
elimina la segunda sobrecarga de f()
, probablemente (?) Sobre la base de que la llamada se realiza solo con 1 argumento, entero 42
, mientras que la segunda sobrecarga requiere 2 argumentos. Por otro lado, gcc
no elimina la segunda sobrecarga, y en su lugar intenta crear una instancia de struct Bad_Type_Fcn<int>
, lo que resulta en un error.
La inconsistencia desaparece si elimino la creación de instancias explícita en la llamada a f()
y escribo (void)f(42);
en lugar.
¿Cuál de los compiladores es correcto?
Recuerdo una discusión central de WG21 sobre esto, y uno de los desarrolladores de Clang defendió su posición citando 14.7.1p7
Si el proceso de resolución de sobrecarga puede determinar la función correcta a la que llamar sin crear una instancia de una definición de plantilla de clase, no se especifica si esa instancia se lleva a cabo realmente.
Por otro lado, para un programa mal formado (que es el caso aquí cuando se realiza la creación de instancias requerida), no existe tal noción de "la función correcta a llamar", por lo que estoy de acuerdo con la posición de otro chico en esa discusión quien dijo que no puede ver que esto le permite a Clang ir por ese camino.
En el ejemplo de p7, muestra un código que está bien formado con y sin hacer la creación de instancias adicionales.
En cualquier caso , incluso si se permite que Clang lo haga, la buena formación de su programa dependería de sucesos particulares (comportamiento no especificado). Por lo tanto, la Norma ya no requiere que su programa sea aceptado, y honestamente no sé qué significa eso. Considero que tal código está mal formado.