Estoy escribiendo una función contenedora de plantilla que se puede aplicar a funciones con diferentes números/tipos de argumentos. Tengo un código que funciona pero estoy tratando de cambiar más argumentos en parámetros de plantilla.
El código de trabajo:
#include <iostream>
int func0(bool b) { return b? 1: 2; }
//There is a few more funcX...
template<typename...ARGS>
int wrapper(int (*func)(ARGS...), ARGS... args) { return (*func)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool>(func0, b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
Ahora quiero int (*func)(ARGS...)
ser también un parámetro de plantilla. (Es por razones de rendimiento. Quiero que el puntero esté respaldado en el contenedor, porque la forma en que lo estoy usando evita que el compilador lo optimice).
Esto es lo que se me ocurrió (la única diferencia es que cambié el único argumento en un parámetro de plantilla):
#include <iostream>
int func0(bool b) { return b? 1: 2; }
//There is a few more funcX...
template<typename...ARGS, int (*FUNC)(ARGS...)>
int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
Esto no compila. Muestra:
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class... ARGS, int (* FUNC)(ARGS...)> int wrapper(ARGS...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class... ARGS, int (* FUNC)(ARGS...)> int wrapper(ARGS...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
ASM generation compiler returned: 1
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class... ARGS, int (* FUNC)(ARGS...)> int wrapper(ARGS...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class... ARGS, int (* FUNC)(ARGS...)> int wrapper(ARGS...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
Execution build compiler returned: 1
( enlace al explorador del compilador )
Me parece un problema con el compilador, pero GCC y Clang están de acuerdo, así que tal vez no lo sea.
De todos modos, ¿cómo puedo hacer que esta plantilla se compile correctamente con un puntero con plantilla a una función?
EDITAR: abordar el problema de compilación de bandera duplicada con la creación de instancias de la plantilla de función
. Creo que el núcleo del problema en esa pregunta es el mismo que en el mío, sin embargo, carece de una solución que permita pasar el puntero para que funcione (no solo su tipo) como parámetro de plantilla.
Solución del problema
Esto no funciona porque un parámetro de paquete (el que incluye ...
) consume todos los argumentos restantes. Todos los argumentos que le siguen no pueden especificarse explícitamente y deben deducirse.
Normalmente escribes tales envoltorios como este:
template <typename F, typename...P>
int wrapper(F &&func, P &&... params)
{
return std::forward<F>(func)(std::forward<P>(params)...) * 10;
}
(Y si la función se llama más de una vez dentro del contenedor, todas las llamadas, excepto la última, no se pueden usar std::forward
).
Esto pasará la función por referencia, que debería ser exactamente lo mismo que usar un puntero de función, pero no tengo razones para creer que impediría que el compilador la optimice.
You can force the function to be encoded in the template argument by passing std::integral_constant<decltype(&func0), func0>{}
instead of func0
, but again, I don't think it's going to change anything.
No hay comentarios:
Publicar un comentario