2009-08-15 27 views
6

decir que quiero una función de C++ para realizar operaciones aritméticas con dos entradas, tratándolos como un tipo determinado:¿Pasa la función puntero a plantilla como argumento de función?

seudo:

function(var X,var Y,function OP) 
{ 
if(something) 
    return OP<int>(X,Y); 
else if(something else) 
    return OP<double>(X,Y); 
else 
    return OP<string>(X,Y); 
} 

funciones que se ajustan OP pueden ser como:

template <class T> add(var X,var Y) 
{ 
return (T)X + (T)Y; //X, Y are of a type with overloaded operators 
} 

Entonces, la pregunta es ¿cómo sería la firma de la función? Si las funciones del operador no tienen plantilla, puedo hacerlo, pero me confundo con esta complejidad adicional.

+1

Mire los argumentos de plantilla de plantilla. (Y eso no es un error tipográfico) – sbi

+0

+1, esa es básicamente la respuesta correcta sobre cómo pasar OP. – MSalters

+0

Agregué esto como una respuesta. Espero no haber cometido ningún error estúpido. – sbi

Respuesta

4

¿Estás buscando esto?

template<class T> T add(T X, T Y) 
{ 
    return X + Y; 
} 

¿O está buscando algo que llame algo así como agregar?

template<class T, class F> 
T Apply(T x, T y, F f) 
{ 
    return f(x, y); 
} 

llamada Via:

int x = Apply(2, 4, add<int>); 
+0

Creo que quiere pasar * agregar * ** sin ** especificar * int * como argumento de plantilla. – izogfif

5

Estoy un poco confundido ... ¿por qué la diferenciación en su tipo pseudo-código?

plantillas de C++ permiten la deducción de tipo completo en plantillas:

template <typename T, typename F> 
T function(T x, T y, F op) { 
    return op(x, y); 
} 

Aquí, F se adapte a cualquier cosa (especialmente funciones) que pueden llamarse con la sintaxis de llamada () función y aceptar exactamente dos argumentos de tipo T (o implícitamente convertible a ella).

+0

Creo que esto es lo que quise decir, no pensé en una función como un argumento de plantilla. –

+0

El único problema es que F no puede ser función de plantilla con argumentos de plantilla desconocidos, sino que tiene que ser una función que no sea de plantilla o una función de plantilla con todos sus tipos de plantilla especificados. – izogfif

+0

@izogfif También puede especificar explícitamente argumentos de plantilla. Deducirlos se puede hacer mediante la metaprogramación de plantillas. Pero de todos modos parece que esto respondió la pregunta de OP, no hay necesidad de complicarlo aún más. –

0

No estoy seguro de qué significa esto var en su pregunta. Ciertamente no es una palabra clave C++ válida, así que supongo que es un tipo similar a boost:any. Además, a la función le falta un tipo de resultado. Agregué otro var, sea lo que sea. La solución podría tener este aspecto:

template< template<typename> class Func > 
var function(var X, var Y, Func OP) 
{ 
if(something) 
    return OP<int>(X,Y); 
else if(something else) 
    return OP<double>(X,Y); 
else 
    return OP<string>(X,Y); 
} 

El argumento divertido plantilla es una plantilla en sí, de ahí su nombre de "plantilla argumento de plantilla". Usted pasa el nombre de una plantilla, no una instancia. Es decir, se pasa std::plus, no std::plus<int>:

return function(a, b, std::plus); 
+0

No funciona en Visual C++ 2008, Visual C++ 2010 debido a un error de compilación. – izogfif

+0

@izogfif: ahora las imágenes, por un momento, han proporcionado el error exacto del compilador. Alguien podría haber venido, haberlo visto, entendido cuál es el problema y haber publicado una solución. Por supuesto, no queremos esto, así que es bueno que no hayas proporcionado eso. – sbi

+0

Buen punto. Aquí está el código que traté de compilar y los errores presentados por el compilador (al final del código): http://pastebin.com/YyhX9ruT – izogfif

5

funciones de plantilla no se pueden pasar como argumentos de plantilla. Debe deducir manualmente los argumentos de plantilla para esta función antes de pasarla a otra función de plantilla.Por ejemplo, usted tiene la función

T sum(T a, T b) 
{ 
    return a + b; 
} 

desea pasar a callfunc:

template<typename F, typename T> 
T callFunc(T a, T b, F f) 
{ 
    return f(a, b); 
} 

No se puede escribir simplemente

int a = callFunc(1, 2, sum); 

Tienes que escribir

int a = callFunc(1, 2, sum<int>); 

Para poder pasar suma sin escribir int, tiene que escribir un functor - struct o clase con operator() que llamará a su función de plantilla. Luego puede pasar este funtor como argumento de plantilla. Aquí hay un ejemplo.

template<class T> 
T sum(T a, T b) 
{ 
    return a + b; 
} 
template<class T> 
struct Summator 
{ 
    T operator()(T a, T b) 
    { 
     return sum<T>(a, b); 
    } 
}; 
template<template<typename> class TFunctor, class T> 
T doSomething(T a, T b) 
{ 
    return TFunctor<T>()(a, b); 
    //Equivalent to this: 
    //TFunctor<T> functor; 
    //return functor(a, b); 
} 


int main() 
{ 
    int n1 = 1; 
    int n2 = 2; 
    int n3 = doSomething<Summator>(n1, n2); //n3 == 3 
    return 0; 
} 
+0

Esta confusión no surgiría en primer lugar si las personas usaran la terminología correcta: " la plantilla funciona como "no existen, son" plantillas de funciones ". Es decir, en tu ejemplo 'callFunc (1, 2, sum);' estás ** no ** pasando una función a 'callFunc', estás pasando una * plantilla * a ella (y como tu ejemplo te muestra * puede * pasar plantillas como argumentos de plantilla, pero solo plantilla * clase *, no * plantillas * de función). –

+0

Hm .. No lo pensé de esta manera. Creo que la pregunta original debería ser "Cómo pasar plantilla de función como argumento de plantilla de función", entonces, ¿no? – izogfif

+0

Entonces, ¿cómo harías que esta solución funcione si sum es un miembro no estático de una clase? –

1

Utilizo lambdas para esto.

auto add = [](const auto& lhs, const auto& rhs) { 
    static_assert(std::is_arithmetic<typename std::decay<decltype(lhs)>::type>::value, 
      "Needs to be arithmetic."); 
    static_assert(std::is_arithmetic<typename std::decay<decltype(rhs)>::type>::value, 
      "Needs to be arithmetic."); 
    return lhs + rhs; 
}; 

template<typename LHS, typename RHS, typename FUNC 
    , typename OUT = typename std::result_of<FUNC(LHS, RHS)>::type> 
constexpr OUT do_arithmetic(LHS lhs, RHS rhs, FUNC func) { 
    return func(lhs, rhs); 
} 

constexpr auto t = do_arithmetic(40, 2, add); 
static_assert(t == 42, "Wrong answer!"); 
static_assert(std::is_same<std::decay<decltype(t)>::type, int>::value, 
     "Should be int."); 
Cuestiones relacionadas