I have a variadic function accepting any number of mixed parameters: the following code works as expected:
template <typename ... Args>
void call_snippet(lua_State *L, const std::string& name, Args... args) {
lua_rawgeti(L, LUA_REGISTRYINDEX, snippets[name]);
int nargs = 0;
for (auto &&x : {args...}) {
lua_pushinteger(L, x);
nargs++;
}
lua_pcall(L, nargs, LUA_MULTRET, 0);
}
but falls short from needs because it assumes all parameters are int
(or convertible to int
). I would need something along the lines:
template <typename ... Args>
void call_snippet(lua_State *L, const std::string& name, Args... args) {
lua_rawgeti(L, LUA_REGISTRYINDEX, snippets[name]);
int nargs = 0;
for (auto &&x : {args...}) {
switch (typeof(x)) {
case int:
lua_pushinteger(L, x);
nargs++;
break;
case float:
lua_pushnumber(L, x);
nargs++;
break;
case std:string:
lua_pushcstring(L, x.c_str());
nargs++;
break;
case char*:
lua_pushcstring(L, x);
nargs++;
break;
default:
//raise error
;
}
lua_pcall(L, nargs, LUA_MULTRET, 0);
}
How should I actually implement the above pseudocode?
You should be able create function overloads for calling lua_push...
and use a fold expression instead of the loop. The sizeof...
operator can be used to determine the number of parameters:
void Push(lua_State* l, std::nullptr_t) = delete;
void Push(lua_State* l, std::string const& str)
{
lua_pushcstring(l, str.c_str());
}
void Push(lua_State* l, char const* str)
{
lua_pushcstring(l, str);
}
void Push(lua_State* l, int value)
{
lua_pushinteger(l, value);
}
void Push(lua_State* l, float value)
{
lua_pushnumber(l, value);
}
template <typename ... Args>
void call_snippet(lua_State *L, const std::string& name, Args&&... args) {
lua_rawgeti(L, LUA_REGISTRYINDEX, snippets[name]);
((Push(L, std::forward<Args>(args))), ...);
int nargs = sizeof...(Args);
lua_pcall(L, nargs, LUA_MULTRET, 0);
}
The following complete example should demonstrate this in a similar scenario:
#include <iostream>
#include <utility>
void PrintNumber(float f)
{
std::cout << f << "(float)\n";
}
void PrintInt(int i)
{
std::cout << i << "(int)\n";
}
void PrintCstring(char const* str)
{
std::cout << str << "(char const*)\n";
}
void Print(std::nullptr_t) = delete;
void Print(std::string const& str)
{
PrintCstring(str.c_str());
}
void Print(char const* str)
{
PrintCstring(str);
}
void Print(int value)
{
PrintInt(value);
}
void Print(float value)
{
PrintNumber(value);
}
template <typename ... Args>
void PrintArgs(Args&&... args)
{
((Print(std::forward<Args>(args))), ...);
int nargs = sizeof...(Args);
std::cout << "nargs = " << nargs << '\n';
}
int main()
{
PrintArgs("foo", std::string("bar"), 42, 99.9f);
}
Note: You may need to add some overloads to resolve ambiguity, e.g. when passing 99.9
instead of 99.9f
, since the former is a double
which results in ambiguity during overload resolution.