I'm trying to return an std::shared_ptr from a method bound with Luabind, but it doesn't seem to recognize the type.
Luabind code:
module(lua)
[
class_<Character, BaseEntity, std::shared_ptr<Character> > ("Character"),
def("createCharacter", &Character::createCharacter)
];
createCharacter code:
std::shared_ptr<Character> Character::createCharacter(Game* gameInstance, const Character::CharacterSetup& characterSetup, string sprite, b2World* world)
{
return std::shared_ptr<Character>(new Character(gameInstance, characterSetup, sprite, world));
}
If I call this method in a Lua script, nothing gets returned, and execution stops there. However, if I change the method to return a Character*, it works as expected. Some googling around tells me that returning a shared_ptr shouldn't be a problem.
What am I doing wrong?
Also, I have this code so Luabind can understand std::shared_ptr:
namespace luabind
{
template <typename T>
T* get_pointer(std::shared_ptr<T> const& p)
{
return p.get();
}
}
I had to solve the very same problem.
It's a bit complicated. Basically you need to define a function with the prototype
template <typename T>
T* get_pointer(std::shared_ptr<T> const&);
This function additionally must reside in the same namespace as std::shared_ptr
, thus std::
. Note that a function in the global namespace or luabind
namespace, as yours, won't work, because luabind uses special tricks to ensure that only ADL is used when checking if a certain type is a smart pointer. The only way to circumvent this is to define your function in the luabind::detail::has_get_pointer_
namespace instead of just luabind
.
But defining your function in this namespace alone, won't work either (at least for Boost <1.53). Although defining the function in namespace std
is technically not allowed by the C++-standard, it is the only possible way for Boost <1.53. Since 1.53, however, Boost defines it's own boost::get_pointer()
overloads for std::shared_ptr
(and std::unique_ptr
). For this version it's enough to make Boost's get_pointer()
visible in the luabind::detail::has_get_pointer_
namespace, since luabind is using
this function anywhere it uses smart pointers (see the luabind/get_pointer.hpp
header). Defining the function in std
wont even work then, because luabind would provoke an ambiguous call.
So if you want a get_pointer()
overload for std::shared_ptr
which works for Boost <1.53 and >= 1.53 and also for MSVC 10 (and maybe 9) (these define shared_ptr
in std::tr1
instead of std
), I can offer you my (historically grown ;-) ) header:
#ifndef SHAREDPTR_CONVERTER_HPP_INCLUDED
#define SHAREDPTR_CONVERTER_HPP_INCLUDED SHAREDPTR_CONVERTER_HPP_INCLUDED
#include <boost/version.hpp>
#if BOOST_VERSION >= 105300
#include <boost/get_pointer.hpp>
namespace luabind { namespace detail { namespace has_get_pointer_ {
template<class T>
T * get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
}}}
#else // if BOOST_VERSION < 105300
#include <memory>
// Not standard conforming: add function to ::std(::tr1)
namespace std {
#if defined(_MSC_VER) && _MSC_VER < 1700
namespace tr1 {
#endif
template<class T>
T * get_pointer(shared_ptr<T> const& p) { return p.get(); }
#if defined(_MSC_VER) && _MSC_VER < 1700
} // namespace tr1
#endif
} // namespace std
#endif // if BOOST_VERSION < 105300
#endif