summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/sol2/docs/source/api/metatable_key.rst
blob: 718eb2b2ffc3bf4daf0a78fc2def4f93a83389c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
metatable_key
=============
A key for setting and getting an object's metatable
---------------------------------------------------

.. code-block:: cpp

	struct metatable_key_t {};
	const metatable_key_t metatable_key;

You can use this in conjunction with :doc:`sol::table<table>` to set/get a metatable. Lua metatables are powerful ways to override default behavior of objects for various kinds of operators, among other things. Here is an entirely complete example, showing getting and working with a :doc:`usertype<usertype>`'s metatable defined by Sol:

.. code-block:: cpp
	:caption: messing with metatables
	:linenos:

	#include <sol.hpp>

	int main () {

		struct bark {
			int operator()(int x) {
				return x;
			}
		};

		sol::state lua;
		lua.open_libraries(sol::lib::base);

		lua.new_usertype<bark>("bark",
			sol::meta_function::call_function, &bark::operator()
		);

		bark b;
		lua.set("b", &b);

		sol::table b_as_table = lua["b"];		
		sol::table b_metatable = b_as_table[sol::metatable_key];
		sol::function b_call = b_metatable["__call"];
		sol::function b_as_function = lua["b"];

		int result1 = b_as_function(1);
		int result2 = b_call(b, 1);
		// result1 == result2 == 1
	}

It's further possible to have a "Dynamic Getter" (`thanks to billw2012 and Nava2 for this example`_!):

.. code-block:: cpp
	:caption: One way to make dynamic properties (there are others!)
	:linenos:

	#include <sol.hpp>
	#include <unordered_map>

	struct PropertySet {
		sol::object get_property_lua(const char* name, sol::this_state s)
		{
			auto& var = props[name];
			return sol::make_object(s, var);
		}

		void set_property_lua(const char* name, sol::stack_object object)
		{
			props[name] = object.as<std::string>();
		}

		std::unordered_map<std::string, std::string> props;
	};

	struct DynamicObject {
		PropertySet& get_dynamic_props() {
			return dynamic_props;
		}

		PropertySet dynamic_props;
	};


	int main () {
		sol::state lua;
		lua.open_libraries(sol::lib::base);

		lua.new_usertype<PropertySet>("PropertySet", 
			sol::meta_function::new_index, &PropertySet::set_property_lua,
			sol::meta_function::index, &PropertySet::get_property_lua
		);

		lua.new_usertype<DynamicObject>("DynamicObject", 
			"props", sol::property(&DynamicObject::get_dynamic_props)
		);

		lua.script(R"(
			obj = DynamicObject:new()
			obj.props.name = 'test name'
			print('name = ' .. obj.props.name)
		)");

		std::string name = lua["obj"]["props"]["name"];
		// name == "test name";
	}


You can even manipulate the ability to set and get items using metatable objects on a usertype or similar:

.. code-block:: cpp
	:caption: messing with metatables - vector type
	:linenos:

	#include <sol.hpp>

	class vector {
	public:
		double data[3];

		vector() : data{ 0,0,0 } {}

		double& operator[](int i)
		{
			return data[i];
		}


		static double my_index(vector& v, int i)
		{
			return v[i];
		}

		static void my_new_index(vector& v, int i, double x)
		{
			v[i] = x;
		}
	};

	int main () {
		sol::state lua;
		lua.open_libraries(sol::lib::base);
		lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
			sol::meta_function::index, &vector::my_index,
			sol::meta_function::new_index, &vector::my_new_index);
		lua.script("v = vector.new()\n"
			"print(v[1])\n"
			"v[2] = 3\n"
			"print(v[2])\n"
		);

		vector& v = lua["v"];
		// v[0] == 0.0;
		// v[1] == 0.0;
		// v[2] == 3.0;
	}


.. _thanks to billw2012 and Nava2 for this example: https://github.com/ThePhD/sol2/issues/71#issuecomment-225402055