C++ 在模板演绎中保留函数指针参数的完整类型

C++ 在模板演绎中保留函数指针参数的完整类型,c++,arrays,templates,c++11,C++,Arrays,Templates,C++11,我试图找到一种方法,在传递到模板函数时,保持函数指针参数的完整类型 这是我想做的一个例子: #include <stdio.h> #include <utility> template<typename _Ret, typename... Args> static _Ret call(_Ret (*fp)(Args&&...), Args &&... args) { return fp(std::forward<

我试图找到一种方法,在传递到模板函数时,保持函数指针参数的完整类型

这是我想做的一个例子:

#include <stdio.h>
#include <utility>

template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args&&...), Args &&... args)
{
    return fp(std::forward<Args>(args)...);
}

int foo(int arr[4])
{
    printf("arr: %i,%i,%i,%i\n", arr[0], arr[1], arr[2], arr[3]);
    return 0;
}

int main(int, char**)
{
    int arr[4] = { 1, 2, 3, 4 };
    int (*foo_ptr)(int arr[4]) = &foo;
    call<int>(foo_ptr, arr);

    return 0;
}
Luaglue函数恰好是这样的:

template<typename _Ret, typename... _Args>
class LuaGlueFunction : public LuaGlueFunctionBase
{
    public:
        typedef _Ret ReturnType;
        typedef _Ret (*MethodType)( _Args... );

        LuaGlueFunction(LuaGlueBase *lg, const std::string &n, MethodType fn) :
            g(lg), name_(n), fn_(std::forward<decltype(fn)>(fn))
        { }

        ~LuaGlueFunction() {}

        std::string name() { return name_; }

        bool glue(LuaGlueBase *luaGlue)
        {
            lua_pushlightuserdata(luaGlue->state(), this);
            lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
            //printf("add function: %s\n", name_.c_str());
            lua_setglobal(luaGlue->state(), name_.c_str());
            return true;
        }

        int invoke(lua_State *state)
        {
            ReturnType ret = applyTuple(g, state, fn_, args);
            lua_pop(state, Arg_Count_);
            stack<_Ret>::put(g, state, ret);
            return 1;
        }

    private:
        LuaGlueBase *g;
        std::string name_;
        MethodType fn_;
        std::tuple<_Args...> args;
        static const unsigned int Arg_Count_ = sizeof...(_Args);

        static int lua_call_func(lua_State *state)
        {
            auto mimp = (LuaGlueFunction<_Ret, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
            return mimp->invoke(state);
        }
};
模板
类LuaGlueFunction:公共LuaGlueFunctionBase
{
公众:
类型定义返回类型;
typedef _Ret(*MethodType)(_Args…);
LuaGlueFunction(LuaGlueBase*lg,const std::string&n,MethodType fn):
g(lg)、名称(n)、fn(标准::转发(fn))
{ }
~LuaGlueFunction(){}
std::string name(){返回名称}
布尔胶(LuaGlueBase*luaGlue)
{
lua_pushlightuserdata(luaGlue->state(),this);
lua_pushcclosure(luaGlue->state(),&lua_call_func,1);
//printf(“添加函数:%s\n”,name_u.c_str());
lua_setglobal(luaGlue->state(),name_u.c_str());
返回true;
}
int调用(lua_状态*状态)
{
ReturnType ret=applyTuple(g,state,fn_u1;,args);
lua_pop(状态、参数计数);
堆栈::put(g,state,ret);
返回1;
}
私人:
LuaGlueBase*g;
std::字符串名称;
方法fn型;
std::元组参数;
静态常量unsigned int Arg\u Count\u=sizeof…(\u Args);
静态整数lua\u调用函数(lua\u状态*状态)
{
自动mimp=(LuaGlueFunction*)lua_-toserdata(状态,lua_-upvalueindex(1));
返回mimp->invoke(状态);
}
};
我试图允许检测数组,然后在内部将其自动装箱到LuaGlueStaticArray类型中(假设我可以防止数组退化为指针,则该部分已经起作用)


希望这有助于更好地解释我要做的事情。

调用函数模板有问题。它需要被定义为

template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args...), Args &&... args)
//                             ^^^ no &&
记住这一点,当您将
arr
传递给
call
时,您不希望将其推断为
int(&)[4]
,因此必须传递一个指针

call<int>(foo_ptr, &arr[0]); // pass a pointer to the beginning
然后称之为

decltype(foo)* foo_ptr = &foo;
call<int>(foo_ptr, arr);


调用函数模板时出现问题。它需要被定义为

template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args...), Args &&... args)
//                             ^^^ no &&
记住这一点,当您将
arr
传递给
call
时,您不希望将其推断为
int(&)[4]
,因此必须传递一个指针

call<int>(foo_ptr, &arr[0]); // pass a pointer to the beginning
然后称之为

decltype(foo)* foo_ptr = &foo;
call<int>(foo_ptr, arr);


int(*)(int*)
int(*)(int[4])
是同一类型的两种拼写
int(*)(int(&)[4])
是不同的类型,但模板不会凭空生成它,您需要传入该类型的实体。事实上,您是正确的。
int(*)(int*)
int(*)(int[4])
是同一类型的两种拼写
int(*)(int(&)[4])
是一种不同的类型,但模板不会凭空生成它,您需要传入该类型的实体。事实上,您是正确的。请注意,如果
foo
的类型是
int(int(&)[4])
则可以简单地将其称为
call(foo,arr)@mpark是的,这就是我在我发布的。或者你的意思是不需要
foo_ptr
?如果是这样,我同意,我这么做只是因为OP在问题中这么做了。不需要
foo_ptr
yes,但也需要显式模板参数:
call
@mpark啊,是的,这值得一提。我已经更新了答案。谢谢。将
call
的实际参数类型与
fp
的形式参数分开推导,可以进行隐式转换,这样
call(foo,&arr[0])
call(foo,arr)
都是有效的()。请注意,如果
foo
的类型是
int(int(&)[4])
然后您可以简单地将其称为
call(foo,arr)@mpark是的,这就是我在我发布的。或者你的意思是不需要
foo_ptr
?如果是这样,我同意,我这么做只是因为OP在问题中这么做了。不需要
foo_ptr
yes,但也需要显式模板参数:
call
@mpark啊,是的,这值得一提。我已经更新了答案。谢谢。将
call
的实际参数类型与
fp
的形式参数分开推导,可以进行隐式转换,这样
call(foo,&arr[0])
call(foo,arr)
都是有效的()。
call(foo, &arr[0]);    // with int foo(int *arr)
call(foo, arr);        // with int foo(int (&arr)[4])