2012-07-05 26 views
8

tengo el siguiente fragmento de código, que aunque completamente trivial, ilustra un patrón que estoy tratando de utilizar en el código más general.C++ 11 inferencia de tipos con lambda y std :: función

template<typename InT, typename ResT> 
ResT unary_apply(InT val, std::function<ResT(InT)> fn) 
{ 
    return fn(val); 
} 

Me gustaría ser capaz de llamar a unary_apply con punteros de función, funtores, lambdas, etc: de ahí el uso de std::function abstraer que todo por la borda.

Cuando trato de utilizar lo anterior de la siguiente manera, C++ (g ++ 4.7) es incapaz de realizar la inferencia de tipos relevantes:

double blah = unary_apply(2, [](int v) { return 3.0 * v; }); 

su defecto con

src/fun.cpp:147:75: error: no matching function for call to ‘unary_apply(int, test()::<lambda(int)>)’ 
src/fun.cpp:147:75: note: candidate is: 
src/fun.cpp:137:6: note: template<class InT, class ResT> ResT unary_apply(InT, std::function<ResT(InT)>) 
src/fun.cpp:137:6: note: template argument deduction/substitution failed: 
src/fun.cpp:147:75: note: ‘test()::<lambda(int)>’ is not derived from ‘std::function<ResT(double)>’ 

y me parece que Tengo que especificar explícitamente los parámetros de la plantilla (en la práctica, creo que es solo el tipo de retorno que no es inferible):

double blah = unary_apply<int, double>(2, [](int v) { return 3.0 * v; }); 

No estoy tan familiarizado con las reglas de inferencia tipo en C++ 11, pero el comportamiento anterior parece razonable (puedo ver que deducir a través de la mecánica interna de std::function es probablemente una gran pregunta). Mi pregunta es: ¿es posible volver a escribir la función unary_apply anterior para mantener la misma flexibilidad (en términos de los tipos de funciones/funtores, etc. que se pueden pasar como un segundo parámetro) mientras que también da más pistas para escribir la inferencia entonces no tengo que proporcionar explícitamente los parámetros de la plantilla en el momento de la llamada?

Respuesta

9

Yendo poco más de pato typey debería funcionar:

template <typename T, typename F> 
auto unary_apply(T&& val, F&& func) -> decltype(func(val)) { 
    return func(std::forward<T>(val)); 
} 
+0

La solución propuesta es correcta, la primera frase no es. La razón por la cual la inferencia de tipo no se puede aplicar en la pregunta no está relacionada con el hecho de que es una lambda (se podría pasar cualquier otro functor/función y aún no se podría inferir el tipo) –

+0

@ DavidRodríguez-dribeas: leer de nuevo . Lambda no es una * función * tipo. Es un tipo de clase sin nombre con 'operator()'. Pero sí, con 'std :: function ' la inferencia probablemente no funcionaría de todos modos. –

+0

Me perdí esa parte, corrigí el comentario: el problema no es que sea una lambda sino que el argumento de la plantilla para 'std :: function' está en un contexto no editable, intenta pasar una función normal (no' std :: function < > '- ¿o quisiste decir que * lambda no es una creación de instancias' std :: function'? –

Cuestiones relacionadas