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?
CodePudding user response:
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.
CodePudding user response:
In c 20, using template lambda and fold expression (since c 17), you might do as follows:
template <typename... Args>
void call_snippet(lua_State* L, const std::string& name, Args&&... args)
{
std::size_t nargs{ 0u }; // or just sizeof...(Args) ??
const auto call_with_x = [&]<typename T>(T&& x)
{
if constexpr (std::is_same_v<int, T>)
{
// ... lua_pushinteger(L, std::forward<T>(x));
}
else if constexpr (std::is_same_v<float, T>)
{
// ... lua_pushnumber(L, std::forward<T>(x));
}
else if constexpr (std::is_same_v<std::string, T>)
{
// ... lua_pushcstring(L, std::forward<T>(x).c_str());
}
// ... so on ...
else
{
// ... do something by default!
}
};
// call lambda "call_with_x"
((call_with_x(std::forward<Args>(args))),...);
}
Alternatively, you could also use generic lambdas (Since c 14) and get the type of x
by std::decay_t<decltype(x)>
.
template <typename... Args>
void call_snippet(lua_State* L, const std::string& name, Args&&... args)
{
const std::size_t nargs{ sizeof...(Args) }; // just ??
const auto call_with_x = [&](auto&& x)
{
using T = std::decay_t<decltype(x)> ;
// ... as before
};
// call lambda "call_with_x"
((call_with_x(std::forward<Args>(args))), ...);
std::cout << "Total args: " << nargs;
}