0

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?

1
  • 2
    Have you tried replacing lua_pushinteger(L, x); with push_something_somewhere(L, x), and then defining overloaded functions push_something_somewhere(), one that takes an int parameter, another that takes a float, a third one that takes a const std::string &, etc...? You never do this kind of thing yourself, manually. That's yucky. You simply let your compiler do all the yucky work for you. Commented Oct 12, 2022 at 18:58

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Can you have a look to my next question (stackoverflow.com/questions/74059053/…), please?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.