Я хотел бы передать функцию в качестве аргумента шаблона другой функции, чтобы ее можно было сохранить и вызвать позже. В некоторых случаях я хочу передать NULL для обратного вызова, но у меня возникли проблемы. Вот пример того, что я хотел бы сделать:
#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;
}
Я нашел этот похожий вопрос, но он касается передачи нуля в качестве аргумента конструктору, а не передачи нуля в качестве аргумента шаблона, и хитрость там (с использованием (Foo*)0
) не работает в качестве аргумента шаблона.
Есть ли способ обойти это или сделать какую-то хитрую специализацию шаблона или какую-нибудь другую хитрую вещь, чтобы получить желаемый эффект?
EDIT:
Выше был упрощенный пример, который иллюстрировал проблему, с которой я столкнулся, но вот конкретная проблема, которую я пытаюсь решить. У меня есть этот проект Я работаю над этим. Это набор функций, которые упрощают мне смешивание C ++ и Lua (по разным причинам я не хочу использовать LuaBind или другие существующие функции, которые я там обнаружил). Важная функция в этом вопросе - luaW_register<T>
около дна. Это немного устаревшая версия, но она работает практически во всех случаях. Это не работает, однако, если конструктор является закрытым, что произошло, когда я попытался смешать это с Box2D b2Body
(который должен быть сделан из b2World
). luaW_defaultallocator<T>()
(и luaW_defaultdeallocator<T>()
) все еще создается, поскольку я использую его в качестве аргумента по умолчанию в luaW_register<T>()
.
Мое предлагаемое решение состояло в том, чтобы вытянуть параметр allocator
в параметры шаблона luaW_Register
. Затем, если я хочу использовать какую-то другую функцию для получения моих объектов для определенного типа, luaW_defaultallocator
даже не будет создан. В таких случаях, как b2Body
s, когда они вообще не могут создать себя, я хотел бы иметь возможность просто передать NULL
в качестве аргумента шаблона (что кажется вполне разумным, но компилятор задыхается от него по причинам это все еще неясно для меня, кажется, что я могу установить значение в NULL
где-нибудь еще в коде, который я должен быть в состоянии также для шаблонов). Хак, который я первоначально реализовал, заключался в передаче логического аргумента моей функции, который отключил бы возможность вызова Foo.new
из моего кода Lua, но это не остановило бы defaultallocator
от компиляции, и если бы я мог использовать проверку нуля и работать так, как мне хотелось бы, имеет приятный побочный эффект: я просто проверяю, есть ли распределитель, и использую его для управления добавлением функции new
в таблицу lua.
tl; dr: моя цель состояла в том, чтобы перейти от этого:
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>)
на это:
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)
чтобы в некоторых случаях не создавать экземпляры luaW_defaultallocator, но похоже, что это невозможно.
Наиболее близким решением, которое я видел до сих пор, является предоставление функции, подобной luaW_cannotalloc<T>(lua_State*)
, которая возвращает NULL и может быть проверена в моей функции luaW_register вместо null. Я полагаю, это сработает, но это означает, что нужно больше набирать и запоминать это имя функции, а NULL кажется намного чище.