c++ - Si la dirección de una función no se puede resolver durante la deducción, ¿es SFINAE o un error del compilador?
templates c++11 (1)
En C ++ 0x, las reglas de SFINAE se han simplificado de tal manera que cualquier expresión o tipo no válido que ocurra en el "contexto inmediato" de la deducción no da como resultado un error del compilador, sino un error de deducción (SFINAE).
Mi pregunta es la siguiente:
Si tomo la dirección de una función sobrecargada y no se puede resolver, ¿es esa falla en el contexto inmediato de la deducción?
(es decir, es un error duro o SFINAE si no se puede resolver)?
Aquí hay un código de ejemplo:
struct X
{
// template<class T> T* foo(T,T); // lets not over-complicate things for now
void foo(char);
void foo(int);
};
template<class U> struct S
{
template<int> struct size_map
{ typedef int type; };
// here is where we take the address of a possibly overloaded function
template<class T> void f(T,
typename size_map<sizeof(&U::foo)>::type* = 0);
void f(...);
};
int main()
{
S<X> s;
// should this cause a compiler error because ''auto T = &X::foo'' is invalid?
s.f(3);
}
Gcc 4.5 indica que esto es un error del compilador, y clang escupe una violación de aserción.
Aquí hay algunas preguntas de interés más relacionadas:
¿El FCD-C ++ 0x especifica claramente qué debería suceder aquí?
¿Se equivocan los compiladores al rechazar este código?
¿Debe definirse un poco mejor el "contexto inmediato" de la deducción?
¡Gracias!
template<class T> void f(T,
typename size_map<sizeof(&U::foo)>::type* = 0);
Esto no funciona, porque U
no participa en la deducción. Mientras que U
es un tipo dependiente, durante la deducción para f
se trata como un tipo fijo escrito con un nombre no dependiente. Necesitas agregarlo a la lista de parámetros de f
/* fortunately, default arguments are allowed for
* function templates by C++0x */
template<class T, class U1 = U> void f(T,
typename size_map<sizeof(&U1::foo)>::type* = 0);
Entonces, en su caso, porque U::foo
no depende de los parámetros de f
sí, recibe un error mientras crea una instancia implícita de S<X>
(intente comentar la llamada, y aún así debería fallar). La FCD dice en 14.7.1/1
La creación de instancias implícita de una especialización de plantilla de clase provoca la creación de instancias implícita de las declaraciones, pero no de las definiciones o argumentos predeterminados, de las funciones de miembro de clase, clases de miembro, miembros de datos estáticos y plantillas de miembro;
Es decir, si crea una instancia implícita de S<X>
, se instanciará la siguiente declaración de plantilla de función
template<class T> void S<X>::f(T,
typename size_map<sizeof(&X::foo)>::type* = 0);
El análisis de esa declaración de plantilla luego encontrará que no puede resolver la referencia a X::foo
y error. Si agrega U1
, la declaración de plantilla aún no intentará resolver la referencia a U1::foo
(dado que U1
es un parámetro de f
), por lo que seguirá siendo válida y SFINAE cuando se intente llamar a f
.