我最近在网上看到这个例子:
typedef std::tuple<
CInput,
CAnimation,
CTransform
> ComponentTuple;
class Entity
{
...
ComponentTuple m_components;
public:
...
// component management
template <typename T> bool has_component() const { return get_component<T>().has; }
template <typename T, typename... TArgs> T& add_component(TArgs&&... mArgs)
{
auto& component = get_component<T>();
component = T(std::forward<TArgs>(mArgs)...);
component.has = true;
return component;
}
template <typename T> T& get_component() { return std::get<T>(m_components); }
template <typename T> const T& get_component() const { return std::get<T>(m_components); }
template <typename T> void remove_component() { get_component<T>() = T(); }
};
我已经研究了这段代码几个小时,但我无法弄清楚模板成员 has_component 和 add_component 是如何工作的 - 特别是与“has”成员一起工作。这是从哪里来的?在我能看到的任何地方,它都没有记录在标准中。然而,不知何故,“has”成员在 add_component 中设置为 true,并且可在 has_component 中进行检查。
显然,这里的目标是使用 has 来确定元组条目是否是默认构造的。
在此提供一些结束。用户 @user17732522 提供了我需要弄清楚发生了什么的线索,以及使用 std::optional:
更好实现的建议#include <tuple>
#include <optional>
typedef std::tuple<
std::optional<CInput>,
std::optional<CAnimation>
> ComponentTuple;
class Entity
{
...
public:
...
// component management
template <typename T> bool has_component() const { return std::get<std::optional<T>>(m_components).has_value(); }
template <typename T, typename... TArgs> T& add_component(TArgs&&... mArgs)
{
std::optional<T>& opt_comp = std::get<std::optional<T>>(m_components);
opt_comp = std::make_optional(T(std::forward<TArgs>(mArgs)...));
return opt_comp.value();
}
template <typename T> T& get_component() { return std::get<std::optional<T>>(m_components).value(); }
template <typename T> const T& get_component() const { return std::get<std::optional<T>>(m_components).value(); }
template <typename T> void remove_component() { std::get<std::optional<T>>(m_components).reset(); }
};
通过此实现,对元组可以管理的类型绝对没有任何限制,但每个类型必须是唯一的,以便成员可以按类型而不是索引查找元素。
代码可以这样写:
auto& anim = player->add_component<CAnimation>(...);
std::cout << "added: " << anim << std::endl;
std::cout << "player " << (player->has_component<CAnimation>() ? "has" : "does not have") << " the CAnimation component." << std::endl;
player->remove_component<CAnimation>();
std::cout << "removed" << std::endl;
std::cout << "player " << (player->has_component<CAnimation>() ? "has" : "does not have") << " the CAnimation component." << std::endl;
非常感谢那些回复的人。