如何遍历 class 模板中的所有类型名称?

How to iterate through all typenames in a class template?

我想为我的游戏设计一个基于组件的武器模板。但是,似乎没有办法 add/remove 一个 class 会员或创建一个代码?

对不起我的表达和缺乏术语,因为我没有毕业于系。计算机科学或软件工程师,我对专业人士所说的那些东西知之甚少。

组件代码如下:

class CBaseWpnCmpt : public std::enable_shared_from_this<CBaseWpnCmpt>
{
public:
    typedef std::shared_ptr<CBaseWpnCmpt> PTR;

private:
    CBaseWpnCmpt() = default;

public:
    CBaseWpnCmpt(const CBaseWpnCmpt& s) = default;
    CBaseWpnCmpt(CBaseWpnCmpt&& s) = default;
    CBaseWpnCmpt& operator=(const CBaseWpnCmpt& s) = default;
    CBaseWpnCmpt& operator=(CBaseWpnCmpt&& s) = default;
    virtual ~CBaseWpnCmpt() {}

protected:
    CBaseWeaponInterface::PTR m_pWeapon { nullptr };

public:
    template <class CComponent>
    static std::shared_ptr<CComponent> Create(CBaseWeaponInterface::PTR pWeapon)
    {
        std::shared_ptr<CComponent> pComponent = std::make_shared<CComponent>();
        pComponent->m_pWeapon = pWeapon;
        return pComponent;
    }
};

这就是武器主体代码的样子:(出现问题)

template <  class CWeapon,
            class ...CComponents
>
class CBaseWeaponTemplate : public CBaseWeaponInterface
{
public:
    std::list<CBaseWpnCmpt::PTR>    m_lstComponents;

public:
    virtual void    SecondaryAttack(void)   // Example method.
    {
        for (auto& pComponent : m_rgpComponents)
        {
            pComponent->SecondaryAttack();
        }
    }
};

我应该如何创建所有这些参数包作为模板的成员?目前我试图将它们加入一个指针 std::list 容器,但我根本不知道如何实现它。

换句话说,填空时如何制作模板:

class CAK47 : public CBaseWeaponTemplate<CAK47, CLongMagazine, CWoodenStock>

将生成这个:

class CAK47
{
    CLongMagazine m_comp1;
    CWoodenStock m_comp2;
//... other stuff
};

或者,生成这个:

class CAK47
{
    CAK47() // constructor
    {
        for (/* somehow iterate through all typenames */)
        {
            CBaseWpnCmpt::PTR p = std::make_shared<typename>();
            m_lstComponents.emplace_back(p);
        }
    }
};

从 C++11 开始,这样做的一种方法是 将用于此特定武器的模板类型 存储在 std::tuple

template <typename Weapon, typename... Attachments>
class WeaponWithAttachments {
  protected:
    WeaponWithAttachments() {
    return;
    }
    std::tuple<Attachments...> attachment_types;
};

然后使用该元组初始化共享指针向量,受保护的构造函数采用元组再次访问模板类型。

class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
  public:
    SomeWeaponWithAttachments()
      : SomeWeaponWithAttachments{attachment_types} {
      return;
    }
  protected:
    template <typename... Attachments>
    SomeWeaponWithAttachments(std::tuple<Attachments...> const&)
      : attachments{std::make_shared<Attachments>()...} {
      return;
    }
    std::vector<std::shared_ptr<BaseAttachment>> attachments;
};

Try it here!


如果 attachments 向量已经在父级内部声明 class 就像这种情况一样,您也可以通过初始化已经在父级内部的附件来避免元组和受保护的构造函数class

template <typename Weapon, typename... Attachments>
class WeaponWithAttachments {
  protected:
    WeaponWithAttachments()
      : attachments{std::make_shared<Attachments>()...} {
      return;
    }
    std::vector<std::shared_ptr<BaseAttachment>> attachments;
};

然后在派生class

中只调用基class的构造函数
class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
  public:
    SomeWeaponWithAttachments()
      : WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment>() {
      return;
    }
};

Try it here!


如果这不适合您,那么您可以使用元组使用 C++17 折叠表达式迭代所有模板参数:

class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
  public:
    SomeWeaponWithAttachments()
      : SomeWeaponWithAttachments{attachment_types} {
      return;
    }
  protected:
    template <typename... Attachments>
    SomeWeaponWithAttachments(std::tuple<Attachments...> const&) {
      (attachments.push_back(std::make_shared<Attachments>()), ...);
      return;
    }
};

Try it here!


在 C++17 中,您还可以在构造函数中添加带有折叠表达式的静态断言,以确保类型实际继承自 BaseAttachment:

static_assert((std::is_base_of_v<BaseAttachment, Attachments> && ...), "Template arguments must inherit from 'BaseAttachment'.");