我正在尝试编写一些将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?)
答案 0 :(得分: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);
}
答案 1 :(得分: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>
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);
}
感谢您的帮助。