C++ 编译器错误递归模板

C++ Compiler Error Recursive Templates

我正在尝试编写一些代码,将 C++ 函数包装成 Lua 可以使用的东西。我试图解决的主要问题之一是将从 Lua 堆栈弹出的值传递给 C++ 函数的参数。对我有用的天真方法是:

        template<typename Ret, typename... Args>
        int luaDRCall(lua_State* s) {
            typedef RDelegate<Ret, Args...>* FunctionPtr;
            FunctionPtr f = (FunctionPtr)popUpvalueObject(s);
            Ret retValue = f->invoke(popValue<Args>(h)...);
            return ScriptValueSender<Ret>::push(h, retValue);
        }

然而,这给我带来了问题,因为 "popValue(h)..." 不能保证从右到左执行。在 MSVC 的 "Debug" 构建下,它工作正常....但 "Release" 版本以相反的顺序调用函数。因此,我编写了一些代码,保证以正确的顺序弹出值:

        template<typename Ret, typename... Args>
        int luaDRCall(lua_State* s) {
            void* del = popUpvalueObject(s);
            return fRCall<Ret, Args...>(s, del);
        }
        template<typename Ret, typename Arg, typename... Args>
        int fRCall(EnvironmentHandle h, void* del) {
            Arg v = popValue<Arg>(h);
            return fRCall<Ret, Args..., Arg>(h, del, v);
        }
        template<typename Ret, typename Arg, typename... Args, typename... Popped>
        int fRCall(EnvironmentHandle h, void* del, Popped... vPopped) {
            Arg v = popValue<Arg>(h);
            return fRCall<Ret, Args..., Popped..., Arg>(h, del, vPopped..., v);
        }
        template<typename Ret, typename... Args>
        int fRCall(EnvironmentHandle h, void* del, Args... vPopped) {
            typedef RDelegate<Ret, Args...>* FunctionPtr;
            FunctionPtr f = (FunctionPtr)del;
            Ret retValue = f->invoke(vPopped...);
            return ScriptValueSender<Ret>::push(h, retValue);
        }

现在,尝试编译此代码会导致:

2>c:\induztry\git\vorb\include\script\Script.h(66): fatal error C1060: compiler is out of heap space
2>c1xx : fatal error C1063: INTERNAL COMPILER ERROR
2>           Please choose the Technical Support command on the Visual C++ 
2>           Help menu, or open the Technical Support help file for more information

有人知道哪里出了问题以及我该如何解决吗?此问题的任何其他解决方案也将不胜感激。谢谢。

编辑 1: 借助以下答案之一,我已将我的代码更改为以下内容,现在只要该函数至少有一个参数,它就可以正常工作。如果没有参数存在,我有编译器错误:

        template<size_t... Is>
        struct index_sequence {};
        template<size_t N, size_t... Is>
        struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
        template<size_t... Is>
        struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
        template<typename... T>
        struct index_sequence_for : make_index_sequence<sizeof...(T)> {};

        template <typename Ret, typename F, typename Tuple, size_t... Is>
        Ret invoke(F f, Tuple& t, index_sequence<Is...>) {
            return f->invoke(std::get<Is>(t)...);
        }
        template<typename Ret, typename... Args>
        int luaDRCall(EnvironmentHandle h) {
            typedef RDelegate<Ret, Args...>* FunctionPtr;
            FunctionPtr f = (FunctionPtr)popUpvalueObject(h);
            std::tuple<Args...> tValue { popValue<Args>(h)... };
            Ret retValue = invoke<Ret>(f, tValue, index_sequence_for<Args...>());
            return ScriptValueSender<Ret>::push(h, retValue);
        }

我有必要将这些全部放入一个函数中使用,并且尝试对没有参数的模板进行特化会导致编译器错误。

1>c:\induztry\git\vorb\include\script\Script.h(68): error C2143: syntax error : missing '}' before '<fake-type>'
1>          c:\induztry\git\vorb\include\script\Script.h(105) : see reference to function template instantiation 'i32 vorb::script::impl::fRCall<Ret,>(vorb::script::EnvironmentHandle,void *)' being compiled
1>          with
1>          [
1>              Ret=int
1>          ]
1>          c:\induztry\git\vorb\include\script\Script.h(122) : see reference to function template instantiation 'int vorb::script::impl::luaDRCall<Ret,>(lua_State *)' being compiled
1>          with
1>          [
1>              Ret=int
1>          ]
1>          C:\InduZtry\Git\Vorb\include/script/Environment.h(76) : see reference to function template instantiation 'vorb::script::ScriptFunc vorb::script::fromRDelegate<Ret,>(void)' being compiled
1>          with
1>          [
1>              Ret=int
1>          ]
1>          VorbScript.cpp(101) : see reference to function template instantiation 'void vorb::script::Environment::addCRDelegate<int,>(const std::string &,RDelegate<int,> &)' being compiled
1>c:\induztry\git\vorb\include\script\Script.h(68): error C2143: syntax error : missing ';' before '<fake-type>'
1>c:\induztry\git\vorb\include\script\Script.h(69): error C2146: syntax error : missing ';' before identifier 'retValue'
1>c:\induztry\git\vorb\include\script\Script.h(69): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\induztry\git\vorb\include\script\Script.h(69): error C2065: 'f' : undeclared identifier
1>c:\induztry\git\vorb\include\script\Script.h(69): error C2065: 'tValue' : undeclared identifier
1>c:\induztry\git\vorb\include\script\Script.h(69): error C3546: '...' : there are no parameter packs available to expand
1>c:\induztry\git\vorb\include\script\Script.h(69): error C2065: 'Args' : undeclared identifier
1>c:\induztry\git\vorb\include\script\Script.h(69): error C3544: 'T': parameter pack expects a type template argument
1>c:\induztry\git\vorb\include\script\Script.h(69): error C2955: 'vorb::script::impl::index_sequence_for' : use of class template requires template argument list
1>          c:\induztry\git\vorb\include\script\Script.h(58) : see declaration of 'vorb::script::impl::index_sequence_for'
1>c:\induztry\git\vorb\include\script\Script.h(70): error C2059: syntax error : 'return'
1>c:\induztry\git\vorb\include\script\Script.h(70): error C2923: 'vorb::script::ScriptValueSender' : 'vorb::script::impl::Ret' is not a valid template type argument for parameter 'T'
1>          c:\induztry\git\vorb\include\script\Script.h(69) : see declaration of 'vorb::script::impl::Ret'
1>c:\induztry\git\vorb\include\script\Script.h(70): error C2955: 'vorb::script::ScriptValueSender' : use of class template requires template argument list
1>          c:\induztry\git\vorb\include\script\ScriptValueSenders.h(36) : see declaration of 'vorb::script::ScriptValueSender'
1>c:\induztry\git\vorb\include\script\Script.h(70): error C2027: use of undefined type 'vorb::script::ScriptValueSender'
1>          c:\induztry\git\vorb\include\script\ScriptValueSenders.h(36) : see declaration of 'vorb::script::ScriptValueSender'
1>c:\induztry\git\vorb\include\script\Script.h(71): error C2059: syntax error : '}'
1>c:\induztry\git\vorb\include\script\Script.h(71): error C2143: syntax error : missing ';' before '}'
1>c:\induztry\git\vorb\include\script\ScriptImpl.h(82): error C2143: syntax error : missing ';' before '{'
1>c:\induztry\git\vorb\include\script\ScriptImpl.h(82): error C2447: '{' : missing function header (old-style formal list?)

以下应该有效,它使用 std::tuple 的构造函数来强制计算顺序(从左到右):

template <typename Ret, typename Tuple, std::size_t ... Is>
Ret Invoke(FunctionPtr f, Tuple& t, std::index_sequence<Is...>)
{
    return f->invoke(std::get<Is>(t)...);
}

template<typename Ret, typename... Args>
int luaDRCall(lua_State* s) {
    typedef RDelegate<Ret, Args...>* FunctionPtr;
    FunctionPtr f = (FunctionPtr)popUpvalueObject(s);
    std::tuple<Args...> t{popValue<Args>(h)...};
    Ret retValue = Invoke<Ret>(f, t, std::index_sequence_for<Args...>());
    return ScriptValueSender<Ret>::push(h, retValue);
}

我能够通过部分专业化解决这个问题:

        template<size_t... Is>
        struct index_sequence {};
        template<size_t N, size_t... Is>
        struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
        template<size_t... Is>
        struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
        template<typename... T>
        struct index_sequence_for : make_index_sequence<sizeof...(T)> {};

        template <typename Ret, typename F, typename Tuple, size_t... Is>
        Ret invoke(F f, Tuple& t, index_sequence<Is...>) {
            return f->invoke(std::get<Is>(t)...);
        }
        template<typename Ret, typename... Args>
        i32 fRCall(EnvironmentHandle h, RDelegate<Ret, Args...>* del) {
            typedef RDelegate<Ret, Args...>* FunctionPtr;
            FunctionPtr f = (FunctionPtr)del;
            std::tuple<Args...> tValue { popValue<Args>(h)... };
            Ret retValue = invoke<Ret>(f, tValue, index_sequence_for<Args...>());
            return ScriptValueSender<Ret>::push(h, retValue);
        }
        template<typename Ret>
        i32 fRCall(EnvironmentHandle h, RDelegate<Ret>* del) {
            typedef RDelegate<Ret>* FunctionPtr;
            FunctionPtr f = (FunctionPtr)del;
            Ret retValue = f->invoke();
            return ScriptValueSender<Ret>::push(h, retValue);
        }

        template<typename Ret, typename... Args>
        int luaDRCall(lua_State* s) {
            void* del = popUpvalueObject(s);
            return fRCall<Ret, Args...>(s, (RDelegate<Ret, Args...>*)del);
        }

感谢大家的帮助。