无法将null函数指针作为模板参数传递

Ale*_*lex 9 c++ templates

我想将一个函数作为模板参数传递给另一个函数,以便以后可以存储和调用它.在某些情况下,我想为回调传递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;
}
Run Code Online (Sandbox Code Playgroud)

我发现了这个类似的问题,但它处理的是将null作为参数传递给构造函数,而不是将null作为模板参数传递,并且那里的技巧(使用(Foo*)0)不能用作模板参数.

有没有办法解决这个问题或做一些棘手的模板专业化或其他一些聪明的事情来获得理想的效果?

编辑:

以上是一个简化的例子,说明了我遇到的问题,但这是我试图解决的具体问题.我有这个项目,我正在努力.这是一组使C++和Lua混合更简单的函数(出于各种原因,我不想使用LuaBind或我发现的其他现有函数).这个问题的重要功能是luaW_register<T>靠近底部.这是一个稍微过时的版本,但它几乎适用于所有情况.但是,如果构造函数是私有的,那么它就不起作用了,当我尝试将它与Box2D混合时b2Body(这需要从a制作b2World).luaW_defaultallocator<T>()(和luaW_defaultdeallocator<T>())仍然得到,因为我用它作为默认参数创建luaW_register<T>().

我提出的解决方案是将allocator参数拉出到模板参数中luaW_Register.然后,如果我想使用其他函数来获取特定类型的对象,luaW_defaultallocator则甚至不会创建.在像b2Bodys 这样的情况下,他们根本无法创建自己,我希望能够NULL作为模板参数传入(这看起来非常合理,但编译器因为我仍然不清楚的原因而窒息) ,似乎我可以设置一个值到NULL代码中的任何其他地方我也应该能够用于模板).我最初实现的一个hack是将一个boolean参数传递给我的函数,它会禁用Foo.new从我的Lua代码调用的能力,但是这并不会停止defaultallocator编译,如果我可以使用null check in工作方式我我希望它有一个很好的副作用,让我只是检查是否有一个分配器,并使用它来控制该new函数是否被添加到lua表.

tl;博士:我的目标是从这里开始:

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>)
Run Code Online (Sandbox Code Playgroud)

对此:

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)
Run Code Online (Sandbox Code Playgroud)

在某些情况下避免实例化luaW_defaultallocator,但它看起来可能无法实现.

到目前为止我看到的最接近的解决方案是提供一个luaW_cannotalloc<T>(lua_State*)返回NULL 的函数,可以在我的luaW_register函数中检查而不是null.我想这会起作用,但这意味着更多的输入并且需要记住该函数名称,并且NULL似乎更清晰.

lar*_*moa 3

这可以通过使用模板重载来解决。\xc2\xb4 不再只有一个 \xc2\xb4T_new` 签名,而是为 NULL 情况提供一个签名,为另一种情况提供一个签名:

\n\n
// Unused signature, no implementation so using this will result in link error\ntemplate<typename T, typename F>\nT* T_new();\n// NULL overload (NULL is an int)\ntemplate<typename T, int func>\nT* T_new()\n{\n    assert(func == 0 && "Signature should only be used with NULL");\n    return NULL;\n}\n// Valid function pointer overload\ntemplate<typename T, T* (*func)()>\nT* T_new()\n{\n    // I don\xc2\xb4t think it\xc2\xb4s possible with NULL functions now, but if it is\n    // we\'ll handle that too\n    if (func)\n        return func();\n    return NULL;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

诀窍是认识到 NULL 实际上是一个 int 并使用它来处理不同重载中的 NULL 情况。

\n

  • 您不能使用函数的部分模板特化。 (2认同)