as_table

make sure an object is pushed as a table

template <typename T>
as_table_t {
        T& value() &;
        const T& value() & const;
        T&& value() &&;
};

template <typename T>
as_table_t<T> as_function ( T&& container );

This function serves the purpose of ensuring that an object is pushed – if possible – like a table into Lua. The container passed here can be a pointer, a reference, a std::reference_wrapper around a container, or just a plain container value. It must have a begin/end function, and if it has a std::pair<Key, Value> as its value_type, it will be pushed as a dictionary. Otherwise, it’s pushed as a sequence.

 1#define SOL_ALL_SAFETIES_ON 1
 2#include <sol/sol.hpp>
 3
 4#include <vector>
 5
 6int main(int, char*[]) {
 7
 8	sol::state lua;
 9	lua.open_libraries();
10	lua.set("my_table",
11	     sol::as_table(std::vector<int> { 1, 2, 3, 4, 5 }));
12	lua.script(
13	     "for k, v in ipairs(my_table) do print(k, v) assert(k "
14	     "== v) end");
15
16	return 0;
17}

Note that any caveats with Lua tables apply the moment it is serialized, and the data cannot be gotten out back out in C++ as a C++ type. You can deserialize the Lua table into something explicitly using the sol::as_table_t marker for your get and conversion operations using sol. At that point, the returned type is deserialized from a table, meaning you cannot reference any kind of C++ data directly as you do with regular userdata/usertypes. All C++ type information is lost upon serialization into Lua.

If you need this functionality with a member variable, use a property on a getter function that returns the result of sol::as_table.

This marker does NOT apply to usertypes.

You can also use this to nest types and retrieve tables within tables as shown by this example.

 1#define SOL_ALL_SAFETIES_ON 1
 2#include <sol/sol.hpp>
 3
 4#include <vector>
 5#include <map>
 6#include <iostream>
 7
 8
 9}
10
11// This second demo is equivalent to the first
12// Nota bene the signature here
13// Every container-type that's meant to be
14// a table must be wrapped in `sol::as_table_t`
15// it's verbose, so feel free to use typedefs to make it easy on
16// you you can mix which parts are considered tables from Lua,
17// and which parts are considered other kinds of types, such as
18// userdata and the like
19void demo_explicit(sol::as_table_t<std::map<std::string,
20          sol::as_table_t<std::vector<std::string>>>>
21          src) {
22	std::cout << "demo, explicit sol::as_table_t<...>"
23	          << std::endl;
24	// Have to access the "source" member variable for
25	// as_table_t
26	const auto& listmap = src.value();
27	SOL_ASSERT(listmap.size() == 2);
28	for (const auto& kvp : listmap) {
29		// Have to access the internal "source" for the inner
30		// as_table_t, as well
31		const std::vector<std::string>& strings
32		     = kvp.second.value();
33		SOL_ASSERT(strings.size() == 3);
34		std::cout << "\t" << kvp.first << " = ";
35		for (const auto& s : strings) {
36			std::cout << "'" << s << "'"
37			          << " ";
38		}
39	}
40	std::cout << std::endl;
41}
42
43int main(int, char**) {
44	std::cout << "=== containers retrieved from lua tables ==="
45	          << std::endl;
46	sol::state lua;
47	// bind the function
48	lua.set_function("f", &demo);
49	lua.set_function("g", &demo_explicit);
50	// Call it with a table that has string sequences set to
51	// distinct keys
52	lua.script(R"(
53t = { 
54	key1 = {'hello', 'there', 'world'},
55	key2 = {'bark', 'borf', 'woof'}
56}
57f(t)
58g(t)
59	)");
60
61	std::cout << std::endl;
62
63	return 0;
64}