Binding classes to Lua¶
To register classes you use a class called class_
. Its name is supposed to
resemble the C++ keyword, to make it look more intuitive. It has an overloaded
member function def()
that is used to register member functions, operators,
constructors, enums and properties on the class. It will return its
this-pointer, to let you register more members directly.
Let's start with a simple example. Consider the following C++ class:
class testclass
{
public:
testclass(const std::string& s): m_string(s) {}
void print_string() { std::cout << m_string << "\n"; }
private:
std::string m_string;
};
To register it with a Lua environment, write as follows (assuming you are using namespace luabind):
module(L)
[
class_<testclass>("testclass")
.def(constructor<const std::string&>())
.def("print_string", &testclass::print_string)
];
This will register the class with the name testclass and constructor that takes
a string as argument and one member function with the name print_string
.
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
> a = testclass('a string')
> a:print_string()
a string
It is also possible to register free functions as member functions. The requirement on the function is that it takes a pointer, const pointer, reference or const reference to the class type as the first parameter. The rest of the parameters are the ones that are visible in Lua, while the object pointer is given as the first parameter. If we have the following C++ code:
struct A
{
int a;
};
int plus(A* o, int v) { return o->a + v; }
You can register plus()
as if it was a member function of A like this:
class_<A>("A")
.def("plus", &plus)
plus()
can now be called as a member function on A with one parameter, int.
If the object pointer parameter is const, the function will act as if it was a
const member function (it can be called on const objects).
Overloaded member functions¶
When binding more than one overloads of a member function, or just binding
one overload of an overloaded member function, you have to disambiguate
the member function pointer you pass to def
. To do this, you can use an
ordinary C-style cast, to cast it to the right overload. To do this, you have
to know how to express member function types in C++, here's a short tutorial
(for more info, refer to your favorite book on C++).
The syntax for member function pointer follows:
return-value (class-name::*)(arg1-type, arg2-type, ...)
Here's an example illlustrating this:
struct A
{
void f(int);
void f(int, int);
};
class_<A>()
.def("f", (void(A::*)(int))&A::f)
This selects the first overload of the function f
to bind. The second
overload is not bound.
Properties¶
To register a global data member with a class is easily done. Consider the following class:
struct A
{
int a;
};
This class is registered like this:
module(L)
[
class_<A>("A")
.def_readwrite("a", &A::a)
];
This gives read and write access to the member variable A::a
. It is also
possible to register attributes with read-only access:
module(L)
[
class_<A>("A")
.def_readonly("a", &A::a)
];
When binding members that are a non-primitive type, the auto generated getter function will return a reference to it. This is to allow chained .-operators. For example, when having a struct containing another struct. Like this:
struct A { int m; };
struct B { A a; };
When binding B
to lua, the following expression code should work:
b = B()
b.a.m = 1
assert(b.a.m == 1)
This requires the first lookup (on a
) to return a reference to A
, and
not a copy. In that case, luabind will automatically use the dependency policy
to make the return value dependent on the object in which it is stored. So, if
the returned reference lives longer than all references to the object (b in
this case) it will keep the object alive, to avoid being a dangling pointer.
You can also register getter and setter functions and make them look as if they were a public data member. Consider the following class:
class A
{
public:
void set_a(int x) { a = x; }
int get_a() const { return a; }
private:
int a;
};
It can be registered as if it had a public data member a like this:
class_<A>("A")
.property("a", &A::get_a, &A::set_a)
This way the get_a()
and set_a()
functions will be called instead of
just writing to the data member. If you want to make it read only you can just
omit the last parameter. Please note that the get function has to be
const, otherwise it won't compile. This seems to be a common source of errors.
Enums¶
If your class contains enumerated constants (enums), you can register them as well to make them available in Lua. Note that they will not be type safe, all enums are integers in Lua, and all functions that takes an enum, will accept any integer. You register them like this:
module(L)
[
class_<A>("A")
.enum_("constants")
[
value("my_enum", 4),
value("my_2nd_enum", 7),
value("another_enum", 6)
]
];
In Lua they are accessed like any data member, except that they are read-only and reached on the class itself rather than on an instance of the class.
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
> print(A.my_enum)
4
> print(A.another_enum)
6
Operators¶
To bind operators you have to include <luabind/operator.hpp>
.
The mechanism for registering operators on your class is pretty simple. You use
a global name luabind::self
to refer to the class itself and then you just
write the operator expression inside the def()
call. This class:
struct vec
{
vec operator+(int s);
};
Is registered like this:
module(L) [ class_<vec>("vec") .def(self + int()) ];
This will work regardless if your plus operator is defined inside your class or as a free function.
If your operator is const (or, when defined as a free function, takes a const
reference to the class itself) you have to use const_self
instead of
self
. Like this:
module(L) [ class_<vec>("vec") .def(const_self + int()) ];
The operators supported are those available in Lua:
+ - * / == < <= %
This means, no in-place operators.
Default implementations (described below) are provided for == and the special __tostring pseudo-operator. If any other operator is called, Luabind will trigger an error ("[const] class <type>: no <metamethod name> defined.", e.g. "class vec: no __div operator defined.").
The equality operator (==
) has a little hitch; it will not be called if
the references are equal. This means that the ==
operator has to do pretty
much what's it's expected to do.
For Luabind's default == operator, two objects are equal only if they are both objects of Luabind-exported classes and have the same addresses, after casting both to a common base if necessary. If they do not have a common base (and are not of the same type), they compare unequal.
Lua does not support operators such as !=
, >
or >=
. That's why you
can only register the operators listed above. When you invoke one of the
mentioned operators, lua will define it in terms of one of the available
operators.
In the above example the other operand type is instantiated by writing
int()
. If the operand type is a complex type that cannot easily be
instantiated you can wrap the type in a class called other<>
. For example:
To register this class, we don't want to instantiate a string just to register the operator.
struct vec
{
vec operator+(std::string);
};
Instead we use the other<>
wrapper like this:
module(L) [ class_<vec>("vec") .def(self + other<std::string>()) ];
To register an application (function call-) operator:
module(L) [ class_<vec>("vec") .def( self(int()) ) ];
There's one special operator. In Lua it's called __tostring
, it's not
really an operator. It is used for converting objects to strings in a standard
way in Lua. If you register this functionality, you will be able to use the lua
standard function tostring()
for converting your object to a string.
To implement this operator in C++ you should supply an operator<<
for
std::ostream. Like this example:
class number {}; std::ostream& operator<<(std::ostream&, number&); ... module(L) [ class_<number>("number") .def(tostring(self)) ];
If you do not define a __tostring
operator, Luabind supplies a default
which result in strings of the form [const] <type> object: <address>
, i.e.
const
is prepended if the object is const, <type>
will be the string
you supplied to class_
(or a string derived from std::type_info::name
for unnamed classes) and <address>
will be the address of the C++ object.
(Note that in multiple inheritance scenarios where the same object is pushed
as multiple different base types, the addresses returned for the same
most-derived object will differ).
Nested scopes and static functions¶
It is possible to add nested scopes to a class. This is useful when you need to wrap a nested class, or a static function.
class_<foo>("foo") .def(constructor<>()) .scope [ class_<inner>("nested"), def("f", &f) ];
In this example, f
will behave like a static member function of the class
foo
, and the class nested
will behave like a nested class of foo
.
It's also possible to add namespaces to classes using the same syntax.
Derived classes¶
If you want to register classes that derives from other classes, you can
specify a template parameter bases<>
to the class_
instantiation. The
following hierarchy:
struct A {};
struct B : A {};
Would be registered like this:
module(L)
[
class_<A>("A"),
class_<B, A>("B")
];
If you have multiple inheritance you can specify more than one base. If B would also derive from a class C, it would be registered like this:
module(L)
[
class_<B, bases<A, C> >("B")
];
Note that you can omit bases<>
when using single inheritance.
Note
If you don't specify that classes derive from each other, luabind will not be able to implicitly cast pointers between the types.
Smart pointers¶
When registering a class you can tell luabind to hold all instances
explicitly created in Lua in a specific smart pointer type, rather than
the default raw pointer. This is done by passing an additional template
parameter to class_
:
class_<X, P>(…)
Where the requirements of P
are:
Expression | Returns |
---|---|
P(raw) |
|
get_pointer(p) |
Convertible to X* |
where:
raw
is of typeX*
p
is an instance ofP
get_pointer()
overloads are provided for the smart pointers in
Boost, and std::auto_ptr<>
. Should you need to provide your own
overload, note that it is called unqualified and is expected to be found
by argument dependent lookup. Thus it should be defined in the same
namespace as the pointer type it operates on.
For example:
class_<X, boost::scoped_ptr<X> >("X") .def(constructor<>())
Will cause luabind to hold any instance created on the Lua side in a
boost::scoped_ptr<X>
. Note that this doesn't mean all instances
will be held by a boost::scoped_ptr<X>
. If, for example, you
register a function:
std::auto_ptr<X> make_X();
the instance returned by that will be held in std::auto_ptr<X>
. This
is handled automatically for all smart pointers that implement a
get_pointer()
overload.
Important
get_const_holder()
has been removed. Automatic conversions
between smart_ptr<X>
and smart_ptr<X const>
no longer work.
Important
__ok
has been removed. Similar functionality can be implemented
for specific pointer types by doing something along the lines of:
bool is_non_null(std::auto_ptr<X> const& p) { return p.get(); } … def("is_non_null", &is_non_null)
When registering a hierarchy of classes, where all instances are to be held by a smart pointer, all the classes should have the baseclass' holder type. Like this:
module(L) [ class_<base, boost::shared_ptr<base> >("base") .def(constructor<>()), class_<derived, base, boost::shared_ptr<base> >("derived") .def(constructor<>()) ];
Internally, luabind will do the necessary conversions on the raw pointers, which are first extracted from the holder type.
This means that for Luabind a smart_ptr<derived>
is not related to a
smart_ptr<base>
, but derived*
and base*
are, as are
smart_ptr<derived>
and base*
. In other words, upcasting does not work
for smart pointers as target types, but as source types.
Unnamed classes¶
You can register unnamed classes by not passing a name to class_
:
class_<X>()
This does not export the class object itself to Lua, meaning that constructors cannot be called and enums are only accessible via objects of this class' type.
This is useful e.g. for registering multiple instantiations of a class template, and construct a matching instance using a factory function, like boost::make_shared of for hiding intermediate classes in inheritance hierarchies.
Splitting class registrations¶
In some situations it may be desirable to split a registration of a class across different compilation units. Partly to save rebuild time when changing in one part of the binding, and in some cases compiler limits may force you to split it. To do this is very simple. Consider the following sample code:
void register_part1(class_<X>& x)
{
x.def(/*...*/);
}
void register_part2(class_<X>& x)
{
x.def(/*...*/);
}
void register_(lua_State* L)
{
class_<X> x("x");
register_part1(x);
register_part2(x);
module(L) [ x ];
}
Here, the class X
is registered in two steps. The two functions
register_part1
and register_part2
may be put in separate compilation
units.
To separate the module registration and the classes to be registered, see Splitting up the registration.