2012-07-31 13 views
14

Se sabe que los argumentos de plantilla pueden ser indicadores de funciones de miembro.Deducción de argumento de plantilla para punteros de función de miembro

Por lo tanto, se puede escribir:

struct Bar 
{ 
    int fun(float x); 
}; 

template <int (Bar::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<&Bar::fun> FooBar; 

Pero lo que si quiero que el tipo de la Bar a sí misma como un argumento de plantilla:

template <typename B, int (B::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<Bar, &Bar::fun> FooBar; 

Ahora, cuando lo uso, tengo que escribir Bar dos veces!

Mi pregunta es: ¿hay alguna manera de obligar al compilador a deducir el tipo de clase automáticamente?

El objetivo es para que esto funcione simplemente:

typedef Foo<&Bar::fun> FooBar; 
typedef Foo<&Moo::fun> FooMoo; 

Respuesta

5

Probablemente deberías simplemente escribir el nombre de la clase allí. Sin embargo, si realmente quieres evitar eso, puedes usar la magia malvada de las macros. La versión simple es más peligroso:

#define TT(X) decltype(X), X 

template<typename T,T t> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

Esto aceptará cualquier tipo de parámetro de plantilla no tipo, y puede encontrar difícil de entender errores si la aplicación sólo funciona con Foo miembro de punteros-a-.

para que sea un poco más seguro que necesita un metafunción que te dice el nombre de clase:

template<typename T> struct member_ptr_traits; 

template<typename Class,typename Ret,typename... Args> 
struct member_ptr_traits<Ret (Class::*)(Args...)> 
{ 
    typedef Class class_type; 
    typedef Ret return_type; 
}; 

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X 

template<typename T,int (T::*FUN)(float)> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

también ambos usar C++ 11 por lo que no funcionará con viejos compiladores. Esta versión simple se puede reescribir para usar el antiguo typeof o extensiones de compilador similares. Reescribir la versión más segura requiere simular plantillas variadas.

+0

En realidad, estoy usando macros feos para esto (es una plantilla interna de una biblioteca, por lo que no existe un riesgo real de que se haga un mal uso). De todos modos, el 'member_ptr_traits' es genial porque realmente necesito el tipo' T'. – rodrigo

7

Respuesta simple: no no lo hay.

El problema es que para que typedef Foo<&Bar::fun> FooBar; funcione, la plantilla debería tener un único argumento sin tipo, pero el tipo de ese argumento sería desconocido cuando se declara la plantilla, lo que no es válido. Por otro lado, la deducción de tipo nunca se aplica a los argumentos de la plantilla (solo a los argumentos para plantillas de función, pero esos son los argumentos para la función, no la plantilla).

+0

Entendido. Entonces sería imposible hacer una función de plantilla, ¿no? – rodrigo

+0

@rodrigo: si desea tomar ese argumento de plantilla como un sí del indicador al miembro. La pregunta es si necesita que el puntero al miembro sea un argumento de plantilla, o puede ser un argumento de función, que puede deducirse. –

+0

Sí, necesito que sea un argumento de plantilla porque se debe usar para crear una instancia de una plantilla anidada. De todos modos, gracias por su información – rodrigo

Cuestiones relacionadas