Closed Milerius closed 4 years ago
Now so far i have:
template<typename TypeToRegister>
void register_type() noexcept
{
const auto table = std::tuple_cat(std::make_tuple(refl::reflect<TypeToRegister>().name.str()));
}
But i dont know how to do for the rest
namespace antara::gaming::metaprog
{
template<class U, class T, bool can_move>
struct wrapper {
T* ptr;
wrapper(T& t) : ptr(std::addressof(t)) {}
using unwrapped_type =
std::conditional_t<can_move,
std::conditional_t<std::is_lvalue_reference<U>{}, T&, T&&>,
std::conditional_t<std::is_rvalue_reference<U>{}, T&&, T&>>;
using tuple_element_type = U;
unwrapped_type unwrap() const{
return std::forward<unwrapped_type>(*ptr);
}
};
template<class... Wrappers, std::size_t... Is>
auto unwrap_tuple(const std::tuple<Wrappers...>& t, std::index_sequence<Is...>) {
return std::tuple<typename Wrappers::tuple_element_type...>(std::get<Is>(t).unwrap()...);
}
template<class... Wrappers>
auto unwrap_tuple(const std::tuple<Wrappers...>& t) {
return unwrap_tuple(t, std::index_sequence_for<Wrappers...>());
}
template<bool can_move, class V, class T>
auto wrap_and_flatten(T& t, char){
return std::make_tuple(wrapper<V, T, can_move>(t));
}
template<class T> struct is_tuple : std::false_type {};
template<class... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {};
template<class T> struct is_tuple<const T> : is_tuple<T> {};
template<class T> struct is_tuple<volatile T> : is_tuple<T> {};
template<bool can_move, class, class Tuple,
class = std::enable_if_t<is_tuple<std::decay_t<Tuple>>{}>>
auto wrap_and_flatten(Tuple& t, int);
template<bool can_move, class Tuple, std::size_t... Is>
auto wrap_and_flatten(Tuple& t, std::index_sequence<Is...>) {
return std::tuple_cat(wrap_and_flatten<can_move, std::tuple_element_t<Is, std::remove_cv_t<Tuple>>>(std::get<Is>(t), 0)...);
}
template<bool can_move, class V, class Tuple, class>
auto wrap_and_flatten(Tuple& t, int) {
using seq_type = std::make_index_sequence<std::tuple_size<Tuple>{}>;
return wrap_and_flatten<can_move>(t, seq_type());
}
template<class Tuple>
auto wrap_and_flatten_tuple(Tuple&& t){
constexpr bool can_move = !std::is_lvalue_reference<Tuple>{};
using seq_type = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>;
return wrap_and_flatten<can_move>(t, seq_type());
}
template <typename T>
auto merge_tuple(T&& t)
{
return unwrap_tuple(wrap_and_flatten_tuple(std::forward<T>(t)));
}
}
namespace antara::gaming::lua
{
class scripting_system final : public ecs::logic_update_system<lua::scripting_system>
{
public:
scripting_system(entt::registry &entity_registry, entt::dispatcher &dispatcher) noexcept;
~scripting_system() noexcept final = default;
void update() noexcept final;
sol::state& get_state() noexcept
{
return lua_state_;
}
template<typename TypeToRegister>
void register_type() noexcept
{
constexpr refl::type_descriptor<TypeToRegister> info = refl::reflect<TypeToRegister>();
auto members_tpl = refl::util::map_to_tuple(refl::type_descriptor<TypeToRegister>::members, [](auto member) {
return std::make_tuple(member.name.c_str(), member.pointer);
});
const auto table = std::tuple_cat(
std::make_tuple(info.name.str()),
members_tpl);
const auto final_table = metaprog::merge_tuple(std::move(table));
try {
std::apply(
[this](auto &&...params) {
this->lua_state_.new_usertype<TypeToRegister>(std::forward<decltype(params)>(params)...);
}, final_table);
}
catch(const std::exception& error) {
std::cerr << error.what() << std::endl;
}
}
private:
sol::state lua_state_;
};
}
Seem's to work but if we have a better solution can be cool
Hmm, I might be missing something, but if all of that is just to pass in the parameters to the new_usertype function, could you not just use something similar to the following snippet:
public:
template<typename TypeToRegister>
void register_type() noexcept
{
register_type_impl<TypeToRegister>(refl::reflect<TypeToRegister>().members);
}
private:
template <typename Type, typename... Members>
void register_type_impl(refl::type_list<Members>)
{
auto params = std::tuple_cat(
std::make_tuple(refl::reflect<Type>().name.c_str()),
std::make_tuple(Members::name.c_str(), Members::pointer)...);
try {
std::apply(
[this](auto&&... params) {
this->lua_state_.new_usertype<Type>(std::forward<decltype(params)>(params)...);
}, final_table);
}
catch(const std::exception& error) {
std::cerr << error.what() << std::endl;
}
}
But members will iterate over each members, and in your solution we will register multiple time the same type no ?
The problem is that sometimes i need to skip the namespace for the name of the type
No, it would not. The only expansion is on the std::make_tuple(Members::name.c_str(), Members::pointer)...
line. But I am finding it difficult to understand the need for wrap_and_flatten_tuple
. Why would special handing be needed?
Because i had a tuple of tuple with my solution and i need only one tuple, that's why i was using wrap_and_flatten_tuple
is it possible to skip namespace for the name a type ?
he problem is that sometimes i need to skip the namespace for the name of the type
Yes, I should probably consider exposing a non-namespace qualified name. No, it is not available OOTB currently.
ok if you want i had a magic snippet that i was using in my reflection system:
namespace details
{
constexpr std::string_view skipNamespaceName(const std::string_view v) noexcept
{
return (v[0] == ':' && v[1] == ':') ? std::string_view{v.data() + 2, v.length() - 2}
: skipNamespaceName({v.data() + 1, v.length() - 1});
}
}
Because i had a tuple of tuple with my solution and i need only one tuple, that's why i was using wrap_and_flatten_tuple
I think you could have gotten away with an std::apply and std::tuple_cat. I will now proceed to close the issue since you managed to get it to work.
Yeah thank's no problem
Hello i try to use refl-hpp instead of my own reflection library
For registering into a scripting type system using reflection i was using the following snippet
It"s was generating a snippet like:
Is it possible using your lib ?