【发布时间】:2011-07-09 09:35:54
【问题描述】:
我想将一个函数作为模板参数传递给另一个函数,以便以后可以存储和调用它。在某些情况下,我想为回调传递 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;
}
我发现this 类似的问题,但它处理将 null 作为参数传递给构造函数,而不是将 null 作为模板参数传递,并且那里的技巧(使用 (Foo*)0)不能用作模板参数.
有没有办法解决这个问题,或者做一些棘手的模板专业化或其他一些聪明的事情来获得预期的效果?
编辑:
上面是一个简化的示例,说明了我遇到的问题,但这是我要解决的具体问题。我有this project 我正在努力。这是一组使混合 C++ 和 Lua 对我来说更简单的函数(出于各种原因,我不想使用 LuaBind 或我在那里找到的其他现有函数)。这个问题的重要功能是luaW_register<T>,靠近底部。这是一个稍微过时的版本,但它几乎适用于所有情况。但是,如果构造函数是私有的,它就不起作用了,当我尝试将它与 Box2D 的 b2Body (需要由 b2World 制作)混合时,它才出现。 luaW_defaultallocator<T>()(和luaW_defaultdeallocator<T>())仍然被创建,因为我将它用作luaW_register<T>() 中的默认参数。
我提出的解决方案是将allocator 参数拉出到luaW_Register 的模板参数中。然后,如果我想使用其他函数来获取特定类型的对象,luaW_defaultallocator 甚至不会被创建。在像b2Bodys 这样他们根本无法创建自己的情况下,我希望能够将NULL 作为模板参数传入(这似乎非常合理,但编译器出于某种原因而窒息这对我来说仍然不清楚,似乎如果我可以在代码中的其他任何地方设置一个值NULL,我也应该能够为模板设置)。我最初实现的一个技巧是向我的函数传递一个布尔参数,这将禁用从我的 Lua 代码调用 Foo.new 的能力,但这不会阻止 defaultallocator 编译,如果我可以使用 null 检查以我希望的方式工作并具有很好的副作用,让我可以简单地检查是否有分配器并使用它来控制 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 看起来更清晰。
【问题讨论】:
-
为什么不能只传递一个返回 null 的函数?然后,您也可以简单地从 T_new 中删除
if。 -
我不知道“棘手的模板专业化”对您意味着什么。对第二个参数进行部分特化是什么问题是 NULL 删除
if并将else子句放在专用版本中? -
@Conspicuous:如果您可以编写一个工作示例,请分享。我想不通。
-
@Conspicuous:不允许对函数进行部分模板特化。
-
顺便说一句,这在 VS2008 上编译得很好