Hello,
I recently downloaded EnTT. Loving it so far, thanks for the awesome work! I now trying to integrate Lua into my project, and expose EnTT to it. I'm currently trying to register the main classes and methods of EnTT to Lua with Sol bindings. Sol needs a function pointer to register the method. I've gotten some of them working, resolving overload conflicts with casting the function pointers:
struct Position {
float x;
float y;
Position( float a, float b ) : x(a), y(b) {}
};
.
.
.
sol::usertype<entt::registry> reg_type = lua.new_usertype<entt::registry>( "registry" );
reg_type.set_function( "create", static_cast< entt::entity( entt::registry::* )() >( &entt::registry::create ) );
reg_type.set_function( "assign_Position", static_cast< Position& ( entt::registry::* )( const entt::entity, float&&, float&& ) >( &entt::registry::assign< Position, float, float > ) );
reg_type.set_function( "remove_Position", &entt::registry::remove< Position > );
etc. For the life of me though, I can't seem to figure out how to make a pointer to the entt::registry::view function for a specific component. I'm just trying to do this basically:
auto funcPtr = &entt::registry::view< Position >;
I've also tried casting explicitly, and explicitly giving the exclude types in for the function pointer:
auto funcPtr = static_cast< entt::basic_view< entt::entity, entt::exclude_t<>, Position >(entt::registry::*)() >( &entt::registry::view< Position > );
auto funcPtr = static_cast< entt::basic_view< entt::entity, entt::exclude_t<>, Position >(entt::registry::*)() >( &entt::registry::view< Position, entt::exclude_t<> > );
None of them can deduce which function I want. Any tips for how would I go about getting this function pointer? I also realize that I'm probably going about things a terrible way, but I'm brand new to EnTT and Lua and just trying to see how I can mesh them together :)
Because of the const overload, you should probably cast it explicitly as I do here.
If you need to get the address of a specialization that also uses exclusion lists, you've to provide a class that makes the two lists explicit and exposes a static function to use to forward your requests to a registry.
Thanks for the quick response. The code in your link doesn't work for me on VS 2017 or 2019. It says it can't deduce the type, and I think it needs the exclusion lists. I tried doing what you said to make a class that makes each list explicit, but I couldn't get it to work:
template < typename... Components >
class Foo
{
public:
template< typename... Excludes >
static auto view()
{
return &entt::registry::view<Components..., entt::exclude_t<Excludes...>>;
}
};
I tried casting that function since it has the const overload, but same thing. I also tried this, but it also didn't work, with or without casting:
template <typename... Types>
struct foo {};
template < typename... Components, template <typename...> class T
, typename... Excludes, template <typename...> class V >
auto view( const T<Components...>&, const V<Excludes...>& )
{
return &entt::registry::view<Components..., entt::exclude_t< Excludes... >>;
}
foo<Position> components;
foo<> excludes;
auto FP = view( components, excludes );
Sorry for my lack of template knowledge, but would you be able to provide an example of the explicit lists that you were talking about, or point me towards somewhere else that does the same?
@LiamTyler
Just enable C++17
@Innokentiy-Alaytsev thanks for the response. I already had 17 enabled:

And it still doesn't work. I updated my 2017 and did a fresh install of 2019, and both fail still
I noticed that with getting a pointer to view::each, I needed to specify all the template parameters, including the excludes:
using F = std::function<void(Position&)>;
reg_type.set_function( "eachPosition", &entt::view<Position>::each<F> );
reg_type.set_function( "eachPosition", static_cast< void( entt::view<Position>::* )( F ) &entt::view<Position>::each<F> );
Neither of the above work, but the following does:
using F = std::function<void(Position&)>;
reg_type.set_function( "eachPosition", &entt::basic_view<entt::entity, entt::exclude_t<>, Position>::each<F> );
I just dont know how to do this for the entt::registry::view, since the template needs both the components and excludes in it
@LiamTyler Indeed. I tried it in Compiler Explorer and thought it will be fine. But the problem is easily reproduced with my MSVS installation.
@Innokentiy-Alaytsev I'm glad im not the only one haha, thank you for checking that.
When I start to type in the explicit types, I see this pop up with Intellisense:

So the view method has the template parameters view< typename ...Components, typename ...Exclude >. I thought you couldn't have two parameter packs back to back like that, but it makes sense to me if we are actually calling the function. Then it could deduce the Exclude types via the arguments right? But since we are not giving arguments while creating a function pointer, this means that anything I type in the entt::registry::view< **right here** > will all be viewed as component types, not exclude types right? Is there a way to make it deduce the Exclude types half way through or something?
Because std::invoke makes opaque the fact that the first argument is the object on which to invoke a member or an actual parameter of the function, you can do something like this and work around the fact that you cannot make explicit the list of excluded components otherwise:
#include <entt/entity/registry.hpp>
#include <entt/entity/entity.hpp>
#include <cassert>
template<typename, typename>
struct export_view;
template<typename... Component, typename... Exclude>
struct export_view<entt::type_list<Component...>, entt::type_list<Exclude...>> {
static entt::view<entt::exclude_t<Exclude...>, Component...> view(entt::registry ®istry) {
return registry.view<Component...>(entt::exclude<Exclude...>);
}
};
struct interesting {};
struct boring {};
int main() {
entt::registry registry;
const auto entity = std::get<0>(registry.create<interesting>());
registry.create<interesting, boring>();
auto get_view = &export_view<entt::type_list<interesting>, entt::type_list<boring>>::view;
auto view = std::invoke(get_view, registry);
for(const auto entt: view) {
assert(entt == entity);
}
}
That works! It ends up being a little clunky in Lua, since I don't know how to register this as a member function anymore, but it works. Thank you so much for the help! I need to up my C++ template knowledge haha
Do you export the registry directly in the Lua context?
Pretty much. I use Sol, so I export the registry by creating an equivalent "usertype":
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::usertype<Position> position_type = lua.new_usertype<Position>("Position", sol::constructors<Position( float, float )>());
position_type["x"] = &Position::x;
position_type["y"] = &Position::y;
sol::usertype<entt::registry> reg_type = lua.new_usertype<entt::registry>("registry");
reg_type.set_function( "create", (entt::entity(entt::registry::*)() )&entt::registry::create );
reg_type.set_function( "assign_Position", static_cast<Position&(entt::registry::*)(const entt::entity, float&&, float&&)> (&entt::registry::assign<Position, float, float> ) );
reg_type.set_function( "remove_Position", &entt::registry::remove<Position> );
reg_type.set_function( "get_Position", static_cast<Position&(entt::registry::*)(entt::entity)>( &entt::registry::get<Position> ) );
reg_type.set_function( "try_get_Position", static_cast<Position*(entt::registry::*)(entt::entity)>( &entt::registry::try_get<Position> ) );
reg_type.set_function( "view_Position", &export_view<entt::type_list<Position>, entt::type_list<>>::view );
auto pos_view = lua.new_usertype< entt::basic_view<entt::entity, entt::exclude_t<>, Position> >( "pos_view" );
pos_view.set_function( "each", &entt::basic_view<entt::entity, entt::exclude_t<>, Position>::each<std::function<void(Position&)>> );
entt::registry registry;
lua["reg"] = ®istry;
But since its not actually a member function of entt::registry anymore, I have to pass in the same registry as the first argument, or make it a free function:
function f( p )
p.x = p.x + 10;
end
reg:view_Position( reg ):each( f )
I think I could make a couple macros to make this registration easy for components. Would be a pain to have to define a new function each new though. I just saw the plugin example with "mod.cpp", maybe ill try to take a stab at using that with Lua
@LiamTyler Try looking into Antara SDK. From what I've heard of it on EnTT's Gitter it does something like what you want, i.e. makes EnTT registry available directly from Lua.
@LiamTyler I also invite you to join the gitter channel. You can find @Milerius there and ask him directly how he integrated EnTT with Sol2.