2012-04-16 21 views
10

Digamos que tengo estos alias plantilla:¿El error de sustitución es un error con los parámetros de plantilla no de tipo dependiente?

enum class enabler {}; 

template <typename T> 
using EnableIf = typename std::enable_if<T::value, enabler>::type; 
template <typename T> 
using DisableIf = typename std::enable_if<!T::value, enabler>::type; 

que pueda hacer lo siguiente en GCC:

#include <iostream> 

template <typename T, EnableIf<std::is_polymorphic<T>> = {}> 
void f(T) { std::cout << "is polymorphic\n"; } 

template <typename T, DisableIf<std::is_polymorphic<T>> = {}> 
void f(T) { std::cout << "is not polymorphic\n"; } 

struct foo { virtual void g() {} }; 

int main() { 
    f(foo {}); 
    f(int {}); 
} 

Imprime:

es polimórfico
no es polimórfico

que coincide con mis expectativas.

Con clang ese código no se compila. Produce los siguientes mensajes de error.

test.cpp:11:58: error: expected expression 
template <typename T, EnableIf<std::is_polymorphic<T>> = {}> 
                 ^
test.cpp:14:59: error: expected expression 
template <typename T, DisableIf<std::is_polymorphic<T>> = {}> 
                 ^
test.cpp:20:3: error: no matching function for call to 'f' 
    f(foo {}); 
^
test.cpp:12:6: note: candidate template ignored: couldn't infer template argument '' 
void f(T) { std::cout << "is polymorphic\n"; } 
    ^
test.cpp:15:6: note: candidate template ignored: couldn't infer template argument '' 
void f(T) { std::cout << "is not polymorphic\n"; } 
    ^
test.cpp:21:3: error: no matching function for call to 'f' 
    f(int {}); 
^
test.cpp:12:6: note: candidate template ignored: couldn't infer template argument '' 
void f(T) { std::cout << "is polymorphic\n"; } 
    ^
test.cpp:15:6: note: candidate template ignored: couldn't infer template argument '' 
void f(T) { std::cout << "is not polymorphic\n"; } 
    ^
4 errors generated. 

¿Debe compilar? ¿Cuál de los dos compiladores está defectuoso?

+0

Ooops, me siento tonto. Tengo la sensación de que esto no tiene nada que ver con los alias de la plantilla, por lo que el título es posiblemente engañoso: S Perdón por eso, investigaré un poco y corregiré el título si resulta que es así. –

+2

'DisableIf > = {}' ¿esa inicialización de la lista del inicializador legal? ¿Pueden las estructuras ser parámetros de valor de plantilla? – jpalecek

+0

@jpalecek No, las estructuras no pueden. Es por eso que uso una enumeración :) –

Respuesta

7

En primer lugar, gracias a @Richard Smith en el para la explicación.
Por desgracia, esto no es legal C++ y como tal Clang es correcta: {} no es una expresión, sino una -init-lista arriostrados y, como tal, nunca será una constante expresión como se necesita en el inicializador de un parámetro de plantilla sin tipo.

§14.3.2 [temp.arg.non-type] p1

A plantilla-argumento para un no-tipo, no molde plantilla-parámetro deberá ser uno de:

  • para una plantilla del tipo no-parámetro de tipo integral o de enumeración, una expresión constante convertida (5.19) del tipo de templat e-parameter; o
  • [...]

Una solución podría ser un valor ficticio en enabler.

+2

Ese no es un buen argumento, no estamos hablando de argumentos de plantilla aquí (nadie intenta, por ejemplo, 'f '), sino argumentos por defecto, que tienen una sintaxis de una declaración de parámetro, que puede, en principio, tener '{ } 'en el rhs (y si' enabler {} 'es una expresión constante, o' x', dado 'enabler x {}', no debería haber un problema con la constante). Sin embargo, 8.3.6/3 dice que debería haber una expresión en caso de declaración de parámetro de plantilla. – jpalecek

+0

@jpalecek: "oone intenta por ejemplo' f '" Uh, llamar a 'f ' hace * exactamente * eso. – GManNickG

+1

@GManNickG: No, no es así. Los parámetros predeterminados no se especifican (al menos explícitamente) como sustituciones de texto. – jpalecek

Cuestiones relacionadas