Me preguntaba si es posible extender el enfoque SFINAE para detectar si una clase tiene una cierta función miembro (como se discute aquí:¿Cómo determinar si una clase tiene una función miembro particular con plantilla?
"¿Hay una técnica en C++ para saber si una clase tiene una función miembro de una ¿Firma dada? " Check if a class has a member function of a given signature
) para admitir funciones de miembro modelado? P.ej. para ser capaz de detectar la función foo en la clase siguiente:
struct some_class {
template < int _n > void foo() { }
};
pensé que podría ser posible hacer esto para una instanciación particular de foo, (por ejemplo, comprobar para ver si void foo<5>()
es un miembro) como sigue:
template < typename _class, int _n >
class foo_int_checker {
template < typename _t, void (_t::*)() >
struct sfinae { };
template < typename _t >
static big
test(sfinae< _t, &_t::foo<_n> > *);
template < typename _t >
static small
test(...);
public:
enum { value = sizeof(test<_class>(0)) == sizeof(big) };
};
Después, realice foo_int_checker< some_class, 5 >::value
para comprobar si some_class
tiene el miembro void foo<5>()
. Sin embargo, en MSVC++ 2008 esta siempre devuelve false
mientras g ++ da los siguientes errores de sintaxis en la línea test(sfinae< _t, &_t::foo<_n> >);
test.cpp:24: error: missing `>' to terminate the template argument list
test.cpp:24: error: template argument 2 is invalid
test.cpp:24: error: expected unqualified-id before '<' token
test.cpp:24: error: expected `,' or `...' before '<' token
test.cpp:24: error: ISO C++ forbids declaration of `parameter' with no type
Ambos parecen fallar porque estoy tratando de obtener la dirección de una instanciación función de plantilla a partir de un tipo que es en sí misma un parámetro de plantilla. ¿Alguien sabe si esto es posible o si no está permitido por el estándar por alguna razón?
EDITAR: Parece que me perdí la sintaxis ::template
para obtener g ++ para compilar el código anterior correctamente. Si cambio el bit donde obtengo la dirección de la función a &_t::template foo<_n>
, entonces el programa se compila, pero obtengo el mismo comportamiento que MSVC++ (value
siempre se establece en false
).
Si comento hacia fuera de la sobrecarga de ...
test
para forzar al compilador para recoger el otro, me sale el siguiente error del compilador en g ++:
test.cpp: In instantiation of `foo_int_checker<A, 5>':
test.cpp:40: instantiated from here
test.cpp:32: error: invalid use of undefined type `class foo_int_checker<A, 5>'
test.cpp:17: error: declaration of `class foo_int_checker<A, 5>'
test.cpp:32: error: enumerator value for `value' not integer constant
donde la línea 32 es la línea enum { value = sizeof(test<_class>(0)) == sizeof(big) };
. Desafortunadamente, esto no parece que me ayude a diagnosticar el problema :(MSVC++ da un error anodino similar:..
error C2770: invalid explicit template argument(s) for 'clarity::meta::big checker<_checked_type>::test(checker<_checked_type>::sfinae<_t,&_t::template foo<5>> *)'
en la misma línea
Lo extraño es que si me da la dirección de una específica clase y no un parámetro de plantilla (es decir, en lugar de &_t::template foo<_n>
hago &some_class::template foo<_n>
) luego obtengo el resultado correcto, pero entonces mi clase checker se limita a verificar una sola clase (some_class
) para la función. Además, si hago lo siguiente:
template < typename _t, void (_t::*_f)() >
void
f0() { }
template < typename _t >
void
f1() {
f0< _t, &_t::template foo<5> >();
}
y llame al f1<some_class>()
y luego NO obtengo un error de compilación en &_t::template foo<5>
. Esto sugiere que el problema solo surge al obtener la dirección de una función de miembro con plantilla de un tipo que a su vez es un parámetro de plantilla en un contexto SFINAE. Argh!
C++ han cancelado en 5 años: D Eche un vistazo a http://stackoverflow.com/questions/36780867/i-neet-to-know-at-compilation-time-if-class-a-has- a-function-member-called-b/36780868 # 36780868 –