Sol can register all kinds of functions. Many are shown in the :doc:`quick 'n' dirty<all-the-things>`, but here we will discuss many of the additional ways you can register functions into a sol-wrapped Lua system.
Member class functions and member class variables will both be turned into functions when set in this manner. You can get intuitive variable with the ``obj.a = value`` access after this section when you learn about :doc:`usertypes to have C++ in Lua<cxx-in-lua>`, but for now we're just dealing with functions!
Another question a lot of people have is about function templates. Function templates -- member functions or free functions -- cannot be registered because they do not exist until you instantiate them in C++. Therefore, given a templated function such as:
..code-block:: cpp
:linenos:
:caption: A C++ templated function
:name: writing-templated-functions-the-func
template <typename A, typename B>
auto my_add( A a, B b ) {
return a + b;
}
You must specify all the template arguments in order to bind and use it, like so:
..code-block:: cpp
:linenos:
:caption: Registering function template instantiations
Notice here that we bind two separate functions. What if we wanted to bind only one function, but have it behave differently based on what arguments it is called with? This is called Overloading, and it can be done with :doc:`sol::overload<../api/overload>` like so:
..code-block:: cpp
:linenos:
:caption: Registering C++ function template instantiations
This is useful for functions which can take multiple types and need to behave differently based on those types. You can set as many overloads as you want, and they can be of many different types.
Function object ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )``. This only happens automagically with ``mytable[key] = obj``. To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call.
There are 2 ways to get a function from Lua. One is with :doc:`sol::function<../api/function>` and the other is a more advanced wrapper with :doc:`sol::protected_function<../api/protected_function>`. Use them to retrieve callables from Lua and call the underlying function, in two ways:
..code-block:: cpp
:linenos:
:caption: Retrieving a sol::function
:name: reading-functions
int main () {
sol::state lua;
lua.script(R"(
function f (a)
return a + 5
end
)");
// Get and immediately call
int x = lua["f"](30);
// x == 35
// Store it into a variable first, then call
sol::function f = lua["f"];
int y = f(20);
// y == 25
}
You can get anything that's a callable in Lua, including C++ functions you bind using ``set_function`` or similar. ``sol::protected_function`` behaves similarly to ``sol::function``, but has a :ref:`error_handler<protected-function-error-handler>` variable you can set to a Lua function. This catches all errors and runs them through the error-handling function:
..code-block:: cpp
:linenos:
:caption: Retrieving a sol::protected_function
:name: reading-protected-functions
int main () {
sol::state lua;
lua.script(R"(
function handler (message)
return "Handled this message: " .. message
end
function f (a)
if a < 0 then
error("negative number detected")
return a + 5
end
)");
sol::protected_function f = lua["f"];
f.error_handler = lua["handler"];
sol::protected_function_result result = f(-500);
if (result.valid()) {
// Call succeeded
int x = r1esult;
}
else {
// Call failed
sol::error err = result;
std::string what = err.what();
// 'what' Should read
// "Handled this message: negative number detected"
}
}
Multiple returns to and from Lua
--------------------------------
You can return multiple items to and from Lua using ``std::tuple``/``std::pair`` classes provided by C++. These enable you to also use :doc:`sol::tie<../api/tie>` to set return values into pre-declared items. To recieve multiple returns, just ask for a ``std::tuple`` type from the result of a function's computation, or ``sol::tie`` a bunch of pre-declared variables together and set the result equal to that:
..code-block:: cpp
:linenos:
:caption: Multiple returns from Lua
:name: multi-return-lua-functions
int main () {
sol::state lua;
lua.script("function f (a, b, c) return a, b, c end");
std::tuple<int, int, int> result;
result = lua["f"](1, 2, 3);
// result == { 1, 2, 3 }
int a, int b;
std::string c;
sol::tie( a, b, c ) = lua["f"](1, 2, "bark");
// a == 1
// b == 2
// c == "bark"
}
You can also return mutiple items yourself from a C++-bound function. Here, we're going to bind a C++ lambda into Lua, and then call it through Lua and get a ``std::tuple`` out on the other side:
..code-block:: cpp
:linenos:
:caption: Multiple returns into Lua
:name: multi-return-cxx-functions
sol::state lua;
lua["f"] = [](int a, int b, sol::object c) {
// sol::object can be anything here: just pass it through
return std::make_tuple( a, b, c );
};
std::tuple<int, int, int> result = lua["f"](1, 2, 3);
Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well.
It was hinted at in the previous code example, but ``sol::object`` is a good way to pass "any type" back into Lua (while we all wait for ``std::variant<...>`` to get implemented and shipped by C++ compiler/library implementers).
It can be used like so, inconjunction with ``sol::this_state``:
..code-block:: cpp
:linenos:
:caption: Return anything into Lua
:name: object-return-cxx-functions
sol::object fancy_func (sol::object a, sol::object b, sol::this_state s) {
This covers almost everything you need to know about Functions and how they interact with Sol. For some advanced tricks and neat things, check out :doc:`sol::this_state<../api/this_state>` and :doc:`sol::variadic_args<../api/variadic_args>`. The next stop in this tutorial is about :doc:`C++ types (usertypes) in Lua<cxx-in-lua>`!