2012-01-03 17 views
12

Me gustaría obtener el primer tipo de parámetro de una función lambda, ¿es posible?Obtener parámetro lambda tipo

p. Ej.

en lugar de:

template<typename T> 
struct base 
{ 
    virtual bool operator()(T) = 0; 
} 

template<typename F, typename T> 
struct filter : public base<T> 
{ 
    virtual bool operator()(T) override {return /*...*/ } 
}; 

template<typename T, typename F> 
filter<T> make_filter(F func) 
{ 
     return filter<F, T>(std::move(func)); 
} 

auto f = make_filter<int>([](int n){return n % 2 == 0;}); 

me gusta:

template<typename F> 
struct filter : public base<typename param1<F>::type> 
{ 
    bool operator()(typename param1<F>::type){return /*...*/ } 
}; 

template<typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

auto f = make_filter([](int n){return n % 2 == 0;}); 

Sobre la base de la respuesta de Xeo esto es lo que tengo trabajando en VS2010:

template<typename FPtr> 
struct arg1_traits_impl; 

template<typename R, typename C, typename A1> 
struct arg1_traits_impl<R (C::*)(A1)>{typedef A1 arg1_type;}; 

template<typename R, typename C, typename A1> 
struct arg1_traits_impl<R (C::*)(A1) const>{typedef A1 arg1_type;}; 

template<typename T> 
typename arg1_traits_impl<T>::arg1_type arg1_type_helper(T); 

template<typename F> 
struct filter : public base<typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type> 
{ 
    bool operator()(typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type){return /*...*/ } 
}; 

template<typename T, typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

He intentado simplificar el código, pero cualquier intento parece romperlo.

+0

que estaba buscando en algún truco con 'std :: :: fuction first_argument_type', sin embargo VS2010 no parece implemenet' first_argument_type'. – ronag

+0

Complicado. * Muy * complicado, especialmente sin plantillas variadas y con VS2010. Necesitará algún tipo de función: rasgos que dividan el tipo real de un puntero de función en sus componentes y use 'function_traits :: param1_type' o similar. VS2010 tiene problemas con ese código, déjame ver si puedo encontrar mi pregunta al respecto ... – Xeo

+0

No puedes usar 'std :: function ' para eso, ya que 'F' es el tipo lambda y no una firma como 'bool (int)'. – Xeo

Respuesta

8

La opción más fácil sería simplemente hacer que el operator() una plantilla en sí:

template<typename F> 
struct filter 
{ 
    template<class Arg> 
    void operator(Arg&& arg){ 
     // use std::forward<Arg>(arg) to call the stored function 
    } 
}; 

template<typename F> 
filter<F> make_filter(F func) 
{ 
     return filter<F>(std::move(func)); 
} 

auto f = make_filter([](int n){return n % 2 == 0;}); 

Ahora, teóricamente, el siguiente código debe trabajar sólo . Sin embargo, no lo hace con MSVC10 gracias a un error:

#include <iostream> 
#include <typeinfo> 

template<class FPtr> 
struct function_traits; 

template<class T, class C> 
struct function_traits<T (C::*)> 
{ 
    typedef T type; 
}; 

template<class F> 
void bar(F f){ 
    typedef typename function_traits< 
     decltype(&F::operator())>::type signature; 
    std::cout << typeid(signature).name(); 
} 

int main(){ 
    bar([](int n){ return n % 2 == 0; }); 
} 

Here 's un ejemplo de cómo se vería con GCC. MSVC10, sin embargo, simplemente no compila el código. Vea this question of mine para más detalles. Básicamente, MSVC10 no trata decltype(&F::operator()) como un tipo dependiente. Aquí hay una solución alternativa que se ideó en un chat discussion:

#include <iostream> 
#include <typeinfo> 
#include <type_traits> 

template<class FPtr> 
struct function_traits; 

template<class R, class C, class A1> 
struct function_traits<R (C::*)(A1)> 
{ // non-const specialization 
    typedef A1 arg_type; 
    typedef R result_type; 
    typedef R type(A1); 
}; 

template<class R, class C, class A1> 
struct function_traits<R (C::*)(A1) const> 
{ // const specialization 
    typedef A1 arg_type; 
    typedef R result_type; 
    typedef R type(A1); 
}; 

template<class T> 
typename function_traits<T>::type* bar_helper(T); 

template<class F> 
void bar(F f){ 
    typedef decltype(bar_helper(&F::operator())) fptr; 
    typedef typename std::remove_pointer<fptr>::type signature; 
    std::cout << typeid(signature).name(); 
} 

int main(){ 
    bar([](int n){ return n % 2 == 0; }); 
} 
+0

¡Genial! Sin embargo, ¿qué pasa si filter :: operator() es virtual? – ronag

+0

@ronag: Entonces tienes un problema. : | ¿Por qué debería ser 'virtual' si la clase en sí misma está modelada en el tipo de función/functor de todos modos? – Xeo

+0

Porque este es un ejemplo simplificado, y en mi filtro de código real tiene una clase base. – ronag

Cuestiones relacionadas