【问题标题】:C++ Compiler Error Recursive TemplatesC++ 编译器错误递归模板
【发布时间】:2015-05-30 22:07:25
【问题描述】:

我正在尝试编写一些代码,将 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 的“调试”版本下,它工作正常......但“发布”版本以相反的顺序调用函数。因此,我编写了一些保证以正确顺序弹出值的代码:

        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?)

【问题讨论】:

  • 内部编译器错误始终是编译器错误。您能做的最好的事情就是找到一种解决方法,为您提供所需的行为;我在那里没有任何建议,但这不一定是你的问题(我没有足够详细地阅读一堆代码)。
  • 我可以发誓总是保证按正确的顺序打开包装...
  • @MooingDuck 我认为问题出在解包函数的未指定执行顺序。见stackoverflow.com/a/833929/234175。所以假设,编译器可以先执行中间的解包函数,然后是最后一个,最后是第一个。按该顺序弹出内容显然会导致 lua 堆栈出现问题。
  • @DarthZaloj 该内部错误表明 MSVC 中可能存在失控的模板实例化。您是否尝试过使用 mingw 或 clang 构建它?
  • @greatwolf:该链接是关于通用函数参数的。我很确定可变参数模板参数解包有特殊规则。我会看看我能找到什么。

标签: c++ templates c++11 lua stack


【解决方案1】:

以下应该可以工作,它使用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);
}

【讨论】:

  • 这是C++14的特性,我只有C++11。
  • @DarthZaloj: index_sequenceindex_sequence_for 可以用 C++11 编写。
  • 我无法获取 std::tuple t { popValue(h)... };编译:```
  • template Arg popValue(EnvironmentHandle h) { return ScriptValueSender::pop(h); }
  • 你有什么错误? (顺便说一句,我假设 h 存在于您的示例中)。
【解决方案2】:

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

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

感谢大家的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    • 2011-06-29
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    相关资源
    最近更新 更多