自动化各种类型的重复代码?
Automate repeated code for various types?
有什么方法可以使它自动化
DeserializeComponent<IDComponent>(json, e);
DeserializeComponent<NameComponent>(json, e);
DeserializeComponent<PointLightComponent>(json, e);
// ...
正如您在此处看到的,相同的代码针对不同的类型执行,但据我所知,在 C++ 中,您不能将类型存储在 std::vector
中。有什么方法可以使它自动化吗?就像循环遍历我在应用程序启动时添加到向量中的组件?另外,我想避免 RTTI。
您可以将类型存储在 std::tuple<tag<Ts>...>
或 TypeList<Ts...>
中
然后使用可变参数模板。
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{});
}
类型不能存储在变量中。类型仅适用于编译器。甚至 RTTI 也不将类型存储在变量中,而是存储类型的“名称”。
我认为您只是想通过不必一遍又一遍地键入 DeserializeComponent<>(json, e);
来缩短代码。好吧,你 可以 使用 参数包扩展 来做到这一点。
template<typename... Components>
void DeserializeComponents(json_t& json, e_t& e)
{
(DeserializeComponent<Components>(json, e), ...);
}
// ...
DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json, e);
神奇之处在于 typename... Components
- 它表示 Components
不仅仅是一个类型参数,而是一个类型参数列表 - 而 (DeserializeComponent<Components>(json, e), ...);
表示复制粘贴函数调用对于每个 Components
参数,并使用逗号运算符 ,
将它们连接在一起
当编译器展开模板时,展开后的模板是这样的:
void DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json_t& json, e_t& e)
{
(
DeserializeComponent<IDComponent>(json, e),
DeserializeComponent<NameComponent>(json, e),
DeserializeComponent<PointLightComponent>(json, e)
);
}
你 可以 也可以通过将对 DeserializeComponents<T>(...)
的函数调用包装在一个函子中来实现,该函子递归地调用自己并通过 [=13] 提供给它的不同类型=].
// 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...
那么你就可以这样做了:
deserialize<IDComponent, NameComponent, PointLightComponent/*, ...*/>{}(json, e);
有什么方法可以使它自动化
DeserializeComponent<IDComponent>(json, e);
DeserializeComponent<NameComponent>(json, e);
DeserializeComponent<PointLightComponent>(json, e);
// ...
正如您在此处看到的,相同的代码针对不同的类型执行,但据我所知,在 C++ 中,您不能将类型存储在 std::vector
中。有什么方法可以使它自动化吗?就像循环遍历我在应用程序启动时添加到向量中的组件?另外,我想避免 RTTI。
您可以将类型存储在 std::tuple<tag<Ts>...>
或 TypeList<Ts...>
中
然后使用可变参数模板。
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{});
}
类型不能存储在变量中。类型仅适用于编译器。甚至 RTTI 也不将类型存储在变量中,而是存储类型的“名称”。
我认为您只是想通过不必一遍又一遍地键入 DeserializeComponent<>(json, e);
来缩短代码。好吧,你 可以 使用 参数包扩展 来做到这一点。
template<typename... Components>
void DeserializeComponents(json_t& json, e_t& e)
{
(DeserializeComponent<Components>(json, e), ...);
}
// ...
DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json, e);
神奇之处在于 typename... Components
- 它表示 Components
不仅仅是一个类型参数,而是一个类型参数列表 - 而 (DeserializeComponent<Components>(json, e), ...);
表示复制粘贴函数调用对于每个 Components
参数,并使用逗号运算符 ,
当编译器展开模板时,展开后的模板是这样的:
void DeserializeComponents<IDComponent, NameComponent, PointLightComponent>(json_t& json, e_t& e)
{
(
DeserializeComponent<IDComponent>(json, e),
DeserializeComponent<NameComponent>(json, e),
DeserializeComponent<PointLightComponent>(json, e)
);
}
你 可以 也可以通过将对 DeserializeComponents<T>(...)
的函数调用包装在一个函子中来实现,该函子递归地调用自己并通过 [=13] 提供给它的不同类型=].
// 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...
那么你就可以这样做了:
deserialize<IDComponent, NameComponent, PointLightComponent/*, ...*/>{}(json, e);