Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无法将空函数指针作为模板参数传递_C++_Templates - Fatal编程技术网

C++ 无法将空函数指针作为模板参数传递

C++ 无法将空函数指针作为模板参数传递,c++,templates,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 <ty

我想将一个函数作为模板参数传递给另一个函数,以便存储它并在以后调用。在某些情况下,我想为回拨传递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;
}
为此:

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_寄存器(lua_State*L,const char*classname,const luaL_reg*表,const luaL_reg*元表,const char**extends=NULL)
为了避免在某些情况下实例化luaW_defaultallocator,但看起来这可能是不可能的


到目前为止,我看到的最接近的解决方案是提供一个类似于
luaW\u cannotalloc(lua\u State*)
的函数,它返回NULL,可以在我的luaW\u寄存器函数中检查,而不是NULL。我想这会管用,但这意味着需要更多的键入和记住函数名,而NULL似乎更干净。

NULL指针的问题是模板指针参数必须有外部链接。null没有链接

如何使事情顺利进行:看来无论你想要实现什么,你都选择了错误的工具

干杯,

你可以(我认为)设置一个适当类型的常数并使用它:

(Foo*)(*make_null_foo)() = 0;

Foo* f3 = T_new<Foo, make_null_foo>();

i、 e.空对象模式。

这可以通过使用模板重载来解决。与仅有一个“T_new”签名不同,您将有一个签名用于空案例,另一个用于其他案例:

// 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;
}
//未使用的签名,没有实现,因此使用此签名将导致链接错误
模板
T*T_new();
//NULL重载(NULL是一个int)
模板
T*T_new()
{
断言(func==0&“签名应仅与NULL一起使用”);
返回NULL;
}
//有效函数指针重载
模板
T*T_new()
{
//我认为现在使用空函数是不可能的,但是如果是的话
//我们也会处理的
if(func)
返回func();
返回NULL;
}

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

这很难看,但它可以工作:

Foo* f3 = T_new<Foo, (Foo* (*)())NULL>();
Foo*f3=T_new();

我真的认为模板在这里没有意义,我也不确定您是否真的仔细考虑过这一点。。。为什么静态调用一个函数时知道它将返回NULL

无论如何,您可以这样做:

template <typename T, T* (*func)()>
T* T_new() {
   return func();
}
template <typename T>
T* T_new() {
   return NULL;
}
模板
T*T_new(){
返回func();
}
模板
T*T_new(){
返回NULL;
}
或者,如果您需要通过中间模板(即,您可能在给定点不知道函数是否为null),您可以遵循null对象模式并提供null函数:

template <typename T>
T* T_new( T* (*func)() = 0 ) {
    if (func)
        return func();
    else
        return NULL;
}
模板
T*null_new(){return 0;}
模板
T*T_new(){
返回f();
}
//用户代码:
X*p=T_new();
或者,忘记使用函数指针作为模板的参数,并将其作为实参数传递给函数:

template <typename T>
T* T_new( T* (*func)() = 0 ) {
    if (func)
        return func();
    else
        return NULL;
}
模板
T*T_新(T*(*func)(=0){
if(func)
返回func();
其他的
返回NULL;
}

为什么不能传递一个返回null的函数呢?然后你也可以从t_new中删除
if
。我不知道什么是“棘手的模板专门化”对你来说意味着。对第二个参数进行部分专门化是空的,在专门化版本中删除
if
并将
else
子句有什么不对?@引人注目的是:如果你能编写一个工作示例,请与大家分享。我想不出来。@引人注目的是:函数I的部分模板专门化It’s not allowed.顺便说一句,在VS2008上编译的这个很好,尝试遵循您的第一个示例会产生这样的错误:“make_null_foo没有在这个范围测试中声明。cpp:40:26:error:make_null_foo不能出现在常量表达式中”。至于第二个解决方案,我不想这样做的原因是我必须为每个位置编写一个函数我不希望能够生成Foo。它还简化了代码中其他地方的事情。为什么不能在任何地方重用相同的非Foo生成函数?我可以,但我必须将其作为模板函数,因为这将用于许多不同的类型。如果不允许生成新对象,并且如果我可以ss NULL然后我只需要一个简单的NULL指针检查,看看是否允许创建新对象。如果找不到更好的解决方案,我可能会选择这个选项,它只会让我的代码变得不那么漂亮,这让我很难过:-/第一个示例的问题是
(Foo*)
是一种类型转换。它可能只适用于
Foo*
。该死的函数指针语法…>:/@Alex:你考虑过不使用模板吗?运行时解决方案往往更灵活。实际上,你到底想在这里做什么?你不能使用函数的部分模板专门化。@David:谢谢,e在我的回答中,现在说的是重载而不是专门化。使用这种方法似乎是迄今为止我试图实现的最好的解决方案。这方面的工作要多一些,因为我实际上要传递3个函数指针(所以我需要制作6个原型)但它在其他方面达到了预期的效果。@Alf:我从未使用过
nullptr
(或其他C++0x功能),但我认为它属于
nullptr\u t
类型。如果我是对的,一个新的重载
模板t*t\u new()
必须添加。我在原始问题中添加了更多信息。我的示例是我实际试图解决的问题的一个非常简化的版本,以避免包含无关的细节,但人们不断询问我的rational,因此我将其包括在内。你的回答没有帮助,因为它没有提供任何有用的信息,也没有提供如何解决的信息围绕问题或完全回避问题的替代解决方案工作。你所说的只是“你有问题,用不同的方法解决”,这对我毫无帮助。我也不同意我选择了
template <typename T>
T* null_new() { return 0; }

template <typename T, T* (*f)() >
T* T_new() {
   return f();
}
// user code:
X* p = T_new<X, null_new >();
template <typename T>
T* T_new( T* (*func)() = 0 ) {
    if (func)
        return func();
    else
        return NULL;
}