Is there is any way by which I can automate this
DeserializeComponent<IDComponent>(json, e);
DeserializeComponent<NameComponent>(json, e);
DeserializeComponent<PointLightComponent>(json, e);
// ...
As you can see here, the same code is executed for different types, but in C you can't store types in a std::vector
as far as my knowledge goes. Is there is any way by which I can automate this? Like looping over the components that I add to a vector in application startup? Also, I want to avoid RTTI.
CodePudding user response:
You can store your types in std::tuple<tag<Ts>...>
or TypeList<Ts...>
and then use variadic template.
template <typename T> struct Tag{ using type = T; };
using MyTypes = std::tuple<Tag<IDComponent>, Tag<NameComponent>/*, ...*/>;
// And then do something like
void foo()
{
// ...
apply([&](auto tag){ DeserializeComponent<typename decltype(tag)::type>(json, e) },
MyTypes{});
}
CodePudding user response:
Types can't be stored in variables. Types are only for the compiler. Even RTTI doesn't store types in variables, but rather "names" of types.
I think you just want to make the code shorter by not having to type DeserializeComponent<>(json, e);
over and over. Well, you can do that with parameter pack expansion.
template<typename... Components>
void DeserializeComponents(json_t& json, e_t& e)
{
(DeserializeComponent<Components>(json, e), ...);
}
// ...
DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json, e);
The magic is in typename... Components
- which says Components
is not just one type argument but a list of type arguments - and (DeserializeComponent<Components>(json, e), ...);
which says to copy-paste the function call for each Components
argument, and join them together with the comma operator ,
When the compiler expands the template, the expanded template looks like this:
void DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json_t& json, e_t& e)
{
(
DeserializeComponent<IDComponent>(json, e),
DeserializeComponent<NameComponent>(json, e),
DeserializeComponent<PointLightComponent>(json, e)
);
}
CodePudding user response:
You could also do it by wrapping the function call to DeserializeComponents<T>(...)
inside a functor which recursively calls itself with the different types provided to it through a parameter pack.
// Other stuff...
// The code below works only with compilers that support C 11 or above
#include <utility>
template <typename T, typename ...Ts>
struct deserialize {
template <typename A, typename B>
void operator()(A&& a, B&& b) const {
DeserializeComponent<T>(std::forward<A>(a), std::forward<B>(b));
deserialize<Ts...>{}(std::forward<A>(a), std::forward<B>(b));
}
};
template <typename T>
struct deserialize<T> {
template <typename A, typename B>
void operator()(A&& a, B&& b) const {
DeserializeComponent<T>(std::forward<A>(a), std::forward<B>(b));
}
};
// Other stuff...
Then you'd be able to do this:
deserialize<IDComponent, NameComponent, PointLightComponent/*, ...*/>{}(json, e);