c++ - parametros - Manera ordenada de parametrizar la plantilla de función con puntero de función genérica
punteros como parametros de funciones en c (5)
Estoy buscando la solución de C ++ 14. C ++ 17 agradeció y realicé la respuesta con la solución C ++ 17, pero el proyecto ahora se construye con C ++ 14 y no puedo cambiarlo en el futuro más cercano.
Desafortunadamente lo que pides funciona a partir de C ++ 17.
Si quieres usar la sintaxis exacta
foo<bar1>();
No creo que sea posible en C ++ 14.
Pero, si acepta una sintaxis un poco diferente ... Sé que las macros son destiladas mal pero ... si acepta llamar a foo()
como
FOO(bar1)();
puedes definir la macro
#define FOO(f) foo<decltype(f()), f>
Un ejemplo completo de trabajo.
#include <iostream>
#define FOO(f) foo<decltype(f()), f>
int bar1 ()
{ std::cout << "bar1()" << std::endl; return 0; }
double bar2 ()
{ std::cout << "bar2()" << std::endl; return 1.0; }
template <typename T, T (*f)()>
void foo ()
{ f(); }
int main()
{
FOO(bar1)(); // print bar1()
FOO(bar2)(); // print bar2()
}
Considere el siguiente caso: tengo
int bar1();
double bar2();
Quiero:
foo<bar1>(); // calls bar1, then uses its result.
foo<bar2>(); // calls bar2, then uses its result.
La forma ingenua de escribir la plantilla foo()
es usar un parámetro adicional:
template <typename T, T (*f)()> void foo () {
// call f, do something with result
}
Esto funciona, pero necesito hacer una sintaxis fea:
foo<decltype(bar1()), bar1>(); // calls bar1, then uses its result
Quiero escribir algo bonito, como arriba, solo foo<bar1>
.
PD No recomiende aceptar argumentos en tiempo de ejecución. Necesito la parametrización del tiempo de compilación solo con puntero de función.
PD Disculpe, olvide mencionar: Estoy buscando la solución C ++ 14. C ++ 17 agradeció y realicé la respuesta con la solución C ++ 17, pero el proyecto ahora se construye con C ++ 14 y no puedo cambiarlo en el futuro más cercano.
¿Qué tal esto?
template<typename F>
auto foo(F* f)
{
return f();
}
int bar() { return 1; }
int main()
{
return foo(bar);
}
Bien, entonces pidió específicamente que bar1
y bar2
sean funciones, pero si estaba dispuesto a relajar esa restricción y permitir que fueran clases con una función miembro estática que implemente el comportamiento deseado, podría hacerlo de la siguiente manera, que ni siquiera requiere C ++ 11 -
struct bar1 {
static int f() { return 42; }
};
struct bar2 {
static double f() { return 3.14159; }
};
template<typename bar>
void foo()
{
double x = bar::f();
std::cout << x << std::endl;
}
int main(int argc, char* const argv[])
{
foo<bar1>();
foo<bar2>();
}
Para obtener
foo<bar1>();
Necesitas la template<auto>
de C ++ 17. Eso se vería como
int bar1() { return 1; }
double bar2() { return 2.0; }
template<auto function> void foo() { std::cout << function() << "/n"; }
int main()
{
foo<bar1>();
foo<bar2>();
}
Que salidas
1
2
Antes de C ++ 17, debe especificar el tipo ya que no hay deducción automática del tipo de parámetros de una plantilla que no son de tipo.
Por lo tanto, intentaré dar la mejor respuesta posible de la que tengo conocimiento en 14. Básicamente, un buen enfoque (IMHO) para este problema es "levantar" el puntero de función a un lambda. Esto te permite escribir foo
de la manera mucho más idiomática de aceptar un llamador:
template <class F>
void foo(F f);
Aún obtienes un rendimiento óptimo, porque el tipo de la lambda es único, y por lo tanto se inserta. Aunque puedes usar más fácilmente foo con otras cosas. Así que ahora tenemos que convertir nuestro puntero de función en un lambda que está codificado para llamarlo. Lo mejor que podemos en ese frente se extrae de esta pregunta: Función a Lambda .
template <class T>
struct makeLambdaHelper;
template <class R, class ... Args>
struct makeLambdaHelper<R(*)(Args...)>
{
template <void(*F)(Args...)>
static auto make() {
return [] (Args ... args) {
return F(std::forward<Args>(args)...);
};
}
};
Lo usamos así:
auto lam = makeLambdaHelper<decltype(&f)>::make<f>();
Para evitar tener que mencionarlo dos veces, podemos usar una macro:
#define FUNC_TO_LAMBDA(f) makeLambdaHelper<decltype(&f)>::make<f>()
Entonces podrías hacer:
foo(FUNC_TO_LAMBDA(bar1));
Ejemplo en vivo: http://coliru.stacked-crooked.com/a/823c6b6432522b8b