Me gustaría pasar una función como argumento de plantilla a otra función para que se pueda almacenar y volver a llamar más tarde. En algunos casos, quiero pasar NULL para la devolución de llamada, pero estoy teniendo problemas. Aquí está un ejemplo de lo que me gustaría ser capaz de hacer:No se puede pasar el puntero a la función nula como argumento de plantilla
#include <iostream>
struct Foo {
int i;
};
template <typename T>
T* T_new() {
return new T();
}
Foo* Foo_new() {
return new Foo();
}
template <typename T, T* (*func)()>
T* T_new() {
if (func)
return func();
else
return NULL;
}
int main(void) {
// Works
Foo* f1 = T_new<Foo>();
std::cout << f1 << std::endl;
// Works
Foo* f2 = T_new<Foo, Foo_new>();
std::cout << f2 << std::endl;
// fails to compile, "no matching function for call to ‘T_new()’"
// Foo* f3 = T_new<Foo, NULL>();
// std::cout << f3 << std::endl;
return 0;
}
He encontrado this pregunta similar, pero que trata de pasar null como un argumento para el constructor, no pasar null como un argumento de plantilla, y el truco allí (usando (Foo*)0
) no funciona como un argumento de plantilla.
¿Hay alguna manera de evitar esto o hacer alguna especialización de plantilla complicada o alguna otra cosa inteligente para obtener el efecto deseado?
EDIT:
Lo anterior fue un ejemplo simplificado que ilustra el problema que estaba teniendo, pero aquí está el problema concreto que estoy tratando de resolver. Tengo this project en que estoy trabajando. Este es un conjunto de funciones que hacen que mezclar C++ y Lua sea más simple para mí (por diversas razones no quiero usar LuaBind o las otras funciones existentes que he descubierto). La función importante de esta pregunta es luaW_register<T>
, cerca de la parte inferior. Esta es una versión ligeramente desactualizada, pero funciona en casi todos los casos. No funciona, sin embargo, si el constructor es privado, que ha llegado justo cuando he intentado mezclar esto con Box2D de b2Body
(que tiene que ser hecho de una b2World
). luaW_defaultallocator<T>()
(y luaW_defaultdeallocator<T>()
) todavía se pone creado ya lo estoy usando como argumento predeterminado en luaW_register<T>()
.
Mi solución propuesta era sacar el parámetro allocator
en los parámetros de plantilla de luaW_Register
. Entonces, si quiero usar alguna otra función para obtener mis objetos para un tipo específico, ni siquiera se creará luaW_defaultallocator
. En casos como b2Body
s, donde no pueden crearse a sí mismos en absoluto, me gustaría ser capaz de pasar justo a NULL
como un argumento de plantilla (que parece perfectamente razonable, pero el compilador está ahogando en ella por razones que aún no están claras para mí, parece que si puedo establecer un valor en NULL
en cualquier otro lugar en el código I debería ser capaz de crear plantillas también). Un truco que implementé inicialmente fue pasar un argumento booleano a mi función que inhabilitaría la capacidad de llamar al Foo.new
desde mi código Lua, pero eso no detiene la compilación de defaultallocator
, y si puedo usar el cheque nulo y el funcionamiento del De la manera que me gustaría, tiene el bonito efecto secundario de permitirme simplemente verificar si hay un asignador y usar eso para controlar si la función new
se agrega o no a la tabla lua.
tl; dr: Mi objetivo era pasar de esto:
template <typename T>
void luaW_register(lua_State* L, const char* classname, const luaL_reg* table, const luaL_reg* metatable, const char** extends = NULL, bool disablenew = false, T* (*allocator)() = luaW_defaultallocator<T>, void (*deallocator)(T*) = luaW_defaultdeallocator<T>)
a esto:
template <typename T, T* (*allocator)() = luaW_defaultallocator<T>, void (*deallocator)(T*) = luaW_defaultdeallocator<T> >
void luaW_register(lua_State* L, const char* classname, const luaL_reg* table, const luaL_reg* metatable, const char** extends = NULL)
para evitar la creación de instancias de luaW_defaultallocator en algunos casos, pero es que parece que podría no ser posible.
La solución más cercana que he visto hasta ahora es proporcionar una función como luaW_cannotalloc<T>(lua_State*)
que devuelve NULL y puede verificarse en mi función luaW_register en lugar de nulo. Supongo que eso funcionaría, pero significa más tipeo y la necesidad de recordar el nombre de la función, y NULL parece mucho más limpio.
¿Por qué no puede simplemente pasar una función que devuelve nulo? Luego puedes simplemente eliminar el 'if' de T_new también. –
No sé qué significa "especialización de plantilla engañosa" para usted. ¿Qué hay de malo en hacer una especialización parcial para el segundo argumento siendo NULL suprimir el 'si' y poner la cláusula' else' en la versión especializada? –
@Conspicuous: si puede codificar un ejemplo de trabajo, por favor, comparta. No pude resolverlo. – Alex