2012-08-17 10 views
15

Me gustaría escribir una función de plantilla que acepte 2 valores y un funtor o una lambda. La función llama al funtor con esos valores y devuelve el resultado.¿Cómo deducir el tipo de valor de retorno del funtor?

template <typename T, typename Fn> 
_ReturnTypeOfPred_ Apply(T x, T y, Fn fn) 
    { 
    return fn(x, y); 
    } 

Pregunta: ¿Cómo puedo definir el tipo de retorno de Apply para convertirse igual al tipo de retorno de Fn? No es necesariamente igual a T, como en este ejemplo del funtor

template <typename T> 
auto Sum(T x, T y) -> decltype(x+y) 
    { 
    return x+y; 
    } 

actualización

fue demasiado simplificado El primero ejemplo. ¿Debería funcionar esta?

template <typename TContainer, typename Fn> 
auto Apply(const TContainer& x, const TContainer& y, Fn fn) -> decltype(fn(x.front(), y.front())) 
    { 
    return fn(x.front(), y.front()); 
    } 

¿Sería siempre funciona si repito return expresión en decltype del tipo de cambio? ¿Hay una manera más elegante?

+2

Los nombres de los encabezados de línea están reservados para la implementación. No debe usarlos en su propio código. –

+2

@KerrekSB: Era un marcador de posición, no un código real – Andrey

+0

Los buenos funtores (como los que están en el STL) siempre definen su 'return_type', por lo que podría usar' Fn :: return_type'. Pero entiendo que quieres una respuesta que también funcione para functors no tan buenos. – Gorpik

Respuesta

18

Estás cerca; sólo tiene que utilizar decltype:

template <typename T, typename Fn> 
auto Apply(T x, T y, Fn fn) -> decltype(fn(x, y)) 
{ 
    return fn(x, y); 
} 

Usted podría utilizar std::result_of (Difference between std::result_of and decltype), pero ¿por qué preocuparse?

template <typename T, typename Fn> 
typename std::result_of<Fn, T, T>::type Apply(T x, T y, Fn fn) 
{ 
    return fn(x, y); 
} 

En cuanto a la pregunta de seguimiento: para una función

auto fn(<args>) -> <return-type> { return <expression>; } 

sustituyendo return-type con decltype(<expression>) se generalmente trabajo, pero puede ser propenso a errores. Por ejemplo, considere:

auto f(char c) -> decltype(std::string() += c) { return std::string() += c; } 

Aquí decltype rendirá std::string & y su función devolverá una referencia lvalue a un local! Esto tendría que ser cambiado a:

auto f(char c) -> std::remove_reference<decltype(std::string() += c)>::type { 
    return std::string() += c; 
} 

En otros casos, <expression> podría producir un valor que no es retornable para razón de ser, por ejemplo, no copiable, que contiene una lambda, etc.

+0

Gracias, ¿podrían echar un vistazo a la pregunta actualizada? – Andrey

+0

@Andrey ver arriba. – ecatmur

+0

La pregunta que enlazó no subraya muy bien las diferencias entre 'std :: result_of' y' decltype'. Para los fines del OP, 'std :: result_of' no es apropiado. –

Cuestiones relacionadas