本文介绍了无法传递null函数指针作为模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将一个函数作为模板参数传递给另一个函数,以便它可以存储并稍后调用。在某些情况下,我想传回NULL的回调,但我有麻烦。这里是我想要做的一个例子:

I would like to pass a function as a template argument to another function so that it can be stored and called back later. In some cases, I want to pass NULL for the call back, but I'm having trouble. Here's an example of what I'd like to be able to do:

#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;
}

我发现我正在努力。这是一组函数,使混合C + +和Lua更简单(因为各种原因,我不想使用LuaBind或其他现有的功能,我发现有)。这个问题的重要功能是 luaW_register< T> ,靠近底部。这是一个稍微过时的版本,但它几乎在所有情况下都有效。它不工作,但是,如果构造函数是私有的,这刚刚来到我试图与Box2D的 b2Body (需要从 b2World )。 luaW_defaultallocator< T>()(和 luaW_defaultdeallocator< T>())作为 luaW_register< T>()中的默认参数。

The above was a simplified example that illustrated the problem I was having, but here's the concrete problem I'm trying to solve. I have this project I'm working on. This is a set of functions that make mixing C++ and Lua simpler for me (For various reasons I don't want to use LuaBind or the other existing functions I've found out there). The important function to this question is luaW_register<T>, near the bottom. This is a slightly out of date version, but it works in almost all cases. It doesn't work, however, if the constructor is private, which has just come when I tried mixing this with Box2D's b2Body (which needs to be made from a b2World). luaW_defaultallocator<T>() (and luaW_defaultdeallocator<T>()) still gets created since I'm using it as the default argument in luaW_register<T>().

我提出的解决方案是将 allocator 参数导出为 luaW_Register 。然后,如果我想使用一些其他函数来获取我的对象的特定类型, luaW_defaultallocator 甚至不会被创建。在 b2Body s的情况下,他们不能创建自己,我想能够只传入 NULL 作为一个模板参数(这似乎完全合理,但编译器是窒息的原因,仍然不清楚我,似乎如果我可以设置一个值 NULL 在代码中的任何地方,我应该能够为模板)。我最初实现的一个黑客是传递一个布尔参数到我的函数,这将禁用从我的Lua代码调用 Foo.new 的能力,但不停止 defaultallocator 从编译,如果我可以使用空检查和工作方式,我想它有让我简单地检查是否有一个分配器和使用以控制是否将 new 函数添加到lua表中。

My proposed solution was to pull the allocator parameter out into template parameters of luaW_Register. Then, if I want to use some other function to get my objects for a specific type, luaW_defaultallocator will not even be created. In cases like b2Bodys, where they can't create themselves at all, I would like to be able to just pass in NULL as a template argument (which seems perfectly reasonable, but the compiler is choking on it for reasons that are still unclear to me, it seems like if I can set a value to NULL anywhere else in code I ought to be able to for templates as well). A hack I initially implemented was to pass in a boolean argument to my function which would disable the ability to call Foo.new from my Lua code, but that doesn't stop defaultallocator from compiling, and if I can use the null check in and working the way I would like it has the nice side effect of letting me simply check if there's an allocator and use that to control whether or not the new function gets added to the lua table.

tl; dr:我的目标是从这里:

tl;dr: my goal was to go from this:

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,但它看起来可能不可能。

to avoid instantiation of luaW_defaultallocator in some cases, but it's looking like it might not be possible.

到目前为止我看到的最接近的解决方案是提供一个函数 luaW_cannotalloc< T>(lua_State *)它返回NULL,可以在我的luaW_register函数中检查,而不是null。我想这将工作,但它意味着更多的打字和需要记住该函数名,并且NULL看起来更干净。

The closest solution I've seen so far is to provide a function like luaW_cannotalloc<T>(lua_State*) which returns NULL and can be checked for in my luaW_register function instead of null. I suppose that would work, but it means more typing and needing to remember that function name, and NULL seems much cleaner.

推荐答案

这可以通过使用模板重载来解决。

This can be solved by using template overloads. Instead of having just one ´T_new` signature you´ll have one signature for the NULL case and one for the other:

// Unused signature, no implementation so using this will result in link error
template<typename T, typename F>
T* T_new();
// NULL overload (NULL is an int)
template<typename T, int func>
T* T_new()
{
    assert(func == 0 && "Signature should only be used with NULL");
    return NULL;
}
// Valid function pointer overload
template<typename T, T* (*func)()>
T* T_new()
{
    // I don´t think it´s possible with NULL functions now, but if it is
    // we'll handle that too
    if (func)
        return func();
    return NULL;
}

诀窍在于意识到NULL实际上是一个int, NULL情况下在不同的重载。

The trick is to realize that NULL is actually an int and use this to handle the NULL case in a different overload.

这篇关于无法传递null函数指针作为模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-24 17:00