Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6744145
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T12:02:55+00:00 2026-05-26T12:02:55+00:00

Ok, so this may not be the best design decision, and I don’t really

  • 0

Ok, so this may not be the best design decision, and I don’t really want to use something like LuaBind… I was just curious if the following is possible in C++ 03 (C++11 makes it possible with variadic templates). Also, I’m sure this has been asked before, but I couldn’t find a straight answer!

Say I have a helper method to call Lua functions from code:

void CallFunction(char* functionName, ...);

which can potentially accept N number of args (using va_arg or any other method of multiple args)

How can I, if it’s even possible, work out the type of each parameter, and pass it to the appropriate lua_push{type}(); function before calling the desired lua function?

I’m not sure if this can be done with var_arg, because you have to know the type when you grab the parameter, I tried to grab it with void* and pass it to a specialized template, but it tries to pass it to template.

Hopefully someone far better at C++ will have a trick or two!
Thanks heaps

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T12:02:56+00:00Added an answer on May 26, 2026 at 12:02 pm

    I would consider wrapping your functionality for calling lua functions in a class. It has several benefits that I’ll show you in a second, but first here is a possible implementation idea for it. Please note that I have not tested this code (or even tried to compile it), it was just something I quickly wrote from top of my head based on my previous attempts to do the same thing.

    namespace detail
    {
        // we overload push_value instead of specializing
        // because this way we can also push values that
        // are implicitly convertible to one of the types
    
        void push_value(lua_State *vm, lua_Integer n)
        {
            lua_pushinteger(vm, n);
        }
    
        void push_value(lua_State *vm, lua_Number n)
        {
            lua_pushnumber(vm, n);
        }
    
        void push_value(lua_State *vm, bool b)
        {
            lua_pushboolean(vm, b);
        }
    
        void push_value(lua_State *vm, const std::string& s)
        {
            lua_pushstring(vm, s.c_str());
        }
    
        // other overloads, for stuff like userdata or C functions
    
        // for extracting return values, we specialize a simple struct
        // as overloading on return type does not work, and we only need
        // to support a specific set of return types, as the return type
        // of a function is always specified explicitly
    
        template <typename T>
        struct value_extractor
        {
        };
    
        template <>
        struct value_extractor<lua_Integer>
        {
            static lua_Integer get(lua_State *vm)
            {
                lua_Integer val = lua_tointeger(vm, -1);
                lua_pop(vm, 1);
                return val;
            }
        };
    
        template <>
        struct value_extractor<lua_Number>
        {
            static lua_Number get(lua_State *vm)
            {
                lua_Number val = lua_tonumber(vm, -1);
                lua_pop(vm, 1);
                return val;
            }
        };
    
        template <>
        struct value_extractor<bool>
        {
            static bool get(lua_State *vm)
            {
                bool val = lua_toboolean(vm, -1);
                lua_pop(vm, 1);
                return val;
            }
        };
    
        template <>
        struct value_extractor<std::string>
        {
            static std::string get(lua_State *vm)
            {
                std::string val = lua_tostring(vm, -1);
                lua_pop(vm, 1);
                return val;
            }
        };
    
        // other specializations, for stuff like userdata or C functions
    }
    
    // the base function wrapper class
    class lua_function_base
    {
    public:
        lua_function_base(lua_State *vm, const std::string& func)
            : m_vm(vm)
        {
            // get the function
            lua_getfield(m_vm, LUA_GLOBALSINDEX, func.c_str());
            // ensure it's a function
            if (!lua_isfunction(m_vm, -1)) {
                // throw an exception; you'd use your own exception class here
                // of course, but for sake of simplicity i use runtime_error
                lua_pop(m_vm, 1);
                throw std::runtime_error("not a valid function");
            }
            // store it in registry for later use
            m_func = luaL_ref(m_vm, LUA_REGISTRYINDEX);
        }
    
        lua_function_base(const lua_function_base& func)
            : m_vm(func.m_vm)
        {
            // copy the registry reference
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, func.m_func);
            m_func = luaL_ref(m_vm, LUA_REGISTRYINDEX);
        }
    
        ~lua_function_base()
        {
            // delete the reference from registry
            luaL_unref(m_vm, LUA_REGISTRYINDEX, m_func);
        }
    
        lua_function_base& operator=(const lua_function_base& func)
        {
            if (this != &func) {
                m_vm = func.m_vm;
                lua_rawgeti(m_vm, LUA_REGISTRYINDEX, func.m_func);
                m_func = luaL_ref(m_vm, LUA_REGISTRYINDEX);
            }
            return *this;
        }
    private:
        // the virtual machine and the registry reference to the function
        lua_State *m_vm;
        int m_func;
    
        // call the function, throws an exception on error
        void call(int args, int results)
        {
            // call it with no return values
            int status = lua_pcall(m_vm, args, results, 0);
            if (status != 0) {
                // call failed; throw an exception
                std::string error = lua_tostring(m_vm, -1);
                lua_pop(m_vm, 1);
                // in reality you'd want to use your own exception class here
                throw std::runtime_error(error.c_str());
            }
        }
    };
    
    // the function wrapper class
    template <typename Ret>
    class lua_function : public lua_function_base
    {
    public:
        lua_function(lua_State *vm, const std::string& func)
            : lua_function_base(vm, func)
        {
        }
    
        Ret operator()()
        {
            // push the function from the registry
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            // call the function on top of the stack (throws exception on error)
            call(0);
            // return the value
            return detail::value_extractor<Ret>::get(m_vm);
        }
    
        template <typename T1>
        Ret operator()(const T1& p1)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            // push the argument and call with 1 arg
            detail::push_value(m_vm, p1);
            call(1);
            return detail::value_extractor<Ret>::get(m_vm);
        }
    
        template <typename T1, typename T2>
        Ret operator()(const T1& p1, const T2& p2)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            // push the arguments and call with 2 args
            detail::push_value(m_vm, p1);
            detail::push_value(m_vm, p2);
            call(2);
            return detail::value_extractor<Ret>::get(m_vm);
        }
    
        template <typename T1, typename T2, typename T3>
        Ret operator()(const T1& p1, const T2& p2, const T3& p3)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            detail::push_value(m_vm, p1);
            detail::push_value(m_vm, p2);
            detail::push_value(m_vm, p3);
            call(3);
            return detail::value_extractor<Ret>::get(m_vm);
        }
    
        // et cetera, provide as many overloads as you need
    };
    
    // we need to specialize the function for void return type
    // as the other class would fail to compile with void as return type
    template <>
    class lua_function<void> : public lua_function_base
    {
    public:
        lua_function(lua_State *vm, const std::string& func)
            : lua_function_base(vm, func)
        {
        }
    
        void operator()()
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            call(0);
        }
    
        template <typename T1>
        void operator()(const T1& p1)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            detail::push_value(m_vm, p1);
            call(1);
        }
    
        template <typename T1, typename T2>
        void operator()(const T1& p1, const T2& p2)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            detail::push_value(m_vm, p1);
            detail::push_value(m_vm, p2);
            call(2);
        }
    
        template <typename T1, typename T2, typename T3>
        void operator()(const T1& p1, const T2& p2, const T3& p3)
        {
            lua_rawgeti(m_vm, LUA_REGISTRYINDEX, m_func);
            detail::push_value(m_vm, p1);
            detail::push_value(m_vm, p2);
            detail::push_value(m_vm, p3);
            call(3);
        }
    
        // et cetera, provide as many overloads as you need
    };
    

    The idea here is that at the time of the construction, the function class will find the function with the name and store it in the registry. The reason why I do it this way, instead of just storing the function name and getting it from the globals index on every invocation, is because this way if some other script at later point would replace the global name with another value (that could be something else than a function), the function object would still refer to the correct function.

    Anyways you might wonder why go through the trouble of all this. This method has various benefits:

    You now have a self-contained type for dealing with lua function objects. You can pass them around in your code easily, without having to worry about the lua stack or lua internals. It’s also cleaner and less error-prone to write code this way.

    Because lua_function overloads op(), you basically have a function object. This has the benefit of being able to use it as a callback for any algorithms or functions that accept them. For instance let’s say you have a lua_function<int> foo("foo");, and let’s say that the function foo in lua takes two arguments, one double and one string. You can now do this:

    // or std::function if C++11
    boost::function<int (double, std::string)> callback = foo;
    // when you call the callback, it calls the lua function foo()
    int result = callback(1.0, "hello world");
    

    This is very powerful mechanism, as you can now bind your lua code to existing C++ code without having to write any sort of additional wrapper code.

    And as you can see, this also lets you easily get the return value from the lua function. With your earlier idea you’d have to extract the values manually from the stack after calling CallFunction. The obvious drawback here is though, that only one return value is supported by this class, but if you need more than that, you can easily expand on the idea of this class (i.e. you could make the class take additional template parameters for multiple return types, or you could use boost::any and return a container of them).

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have 3 tables (note this may not be the best sql db design)
I'm not sure how to best explain this, so this may be a bit
This may not be the correct way to use controllers, but I did notice
This may not be a programming question, but I don't know where to ask
Okay, This may be really simple or it may not even be possible, or
Note: This was an interview question and may not have an actual use case
I am trying to adhere to best multi-layer design practices, and don't want my
This may not be the kind of question one should ask on StackOverflow, but
This may not be possible for the carousel but is there a way to
Sorry, this may or may not be a programming question directly, but I am

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.