c++ - 如何解压可变参数模板,以便初始化相应的成员?

标签 c++ c++11 templates variadic-templates argument-unpacking

我对可变参数模板和打包参数等等都很陌生。 我想在我的程序中拥有一个“实体组件系统”,在尝试向实体添加组件时,我意识到我的尝试有一个重大缺陷。

无论如何,这是我失败的尝试。

struct A{
    float x;
    float y;
    
    A(float _x, float _y):x(_x), y(_y){}
};

struct B{
    float x;
    float y;
    float z;
    
    B(float _x, float _y, float _z):x(_x), y(_y), z(_z){}
};

struct Entity{
    A* a = NULL;
    B* b = NULL;
    
    Entity(){}
    
    template<typename T, typename... args>
    void Add(args... _args){
        if(typeid(T) == typeid(A))
            a = new A(_args...);
        else if(typeid(T) == typeid(B))
            b = new B(_args...);
        else
            throw("Invalid component added");
    }
};

实现看起来像这样..

Entity ent;
ent.Add<A>(12.24f, 123.246f);
ent.Add<B>(1.f, 1.2f, 1.23f);

我希望实现能够以某种方式工作..必须对其进行哪些更改?

最佳答案

您可以使用以下内容(全部在编译时):

  1. std::is_same 检查两种类型是否相同(需要 #include <type_traits> )。
  2. if constexpr 基于它进行分支(c++17 及以上)。
  3. static_assert 如果你想得到编译错误 Add被设置为 A 以外的类型或B (请参阅下面的注释)。

您修改后的代码:

#include <type_traits>

struct A {
    float x;
    float y;

    A(float _x, float _y) :x(_x), y(_y) {}
};

struct B {
    float x;
    float y;
    float z;

    B(float _x, float _y, float _z) :x(_x), y(_y), z(_z) {}
};

struct Entity {
    A* a = nullptr;
    B* b = nullptr;

    Entity() {}

    template<typename T, typename... args>
    void Add(args... _args) {
        if constexpr (std::is_same_v<T, A>)
            a = new A(_args...);
        else if constexpr (std::is_same_v<T, B>)
            b = new B(_args...);
        else
            //static_assert(!sizeof(T), "T must be A or B");  // Enable this line to get a compilation error in this case
            throw("Invalid component added");
    }
};

int main() {
    Entity ent;
    ent.Add<A>(12.24f, 123.246f);
    ent.Add<B>(1.f, 1.2f, 1.23f);
}

注释:

  1. 我使用了标准nullptr推荐代替 NULL .
  2. 使用简单的static_assert(false, ...)不保证能够按照 @RemyLebeau 的评论 ( How can I create a type-dependent expression that is always false? ) 中提到的原因工作。
    该文章中建议的解决方案之一是使用 static_assert(!sizeof(T), ...)假设 sizeof 永远不为 0。本文还提出了一个稍微复杂的解决方案来避免这种假设。

Live demo - Godbolt

关于c++ - 如何解压可变参数模板,以便初始化相应的成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76233054/

相关文章:

Visual C++ 中的 C++ 代码库打开错误

c++ - 如何使用带有附加参数的 for_each?

c++ - 如何防止 C++ 模板的特化?

c++ - 如何重构多余的 getter/setter 方法?

c++ - 使用 C++ 模板的逻辑函数

c++ - Visual Studio 引用 cpp 文件

c++ - shared_ptr.reset() 不删除

C++11 - 如何为多维数组的右值引用提供有效的构造函数?

c++ - 没有定义的函数声明

c# - "Neighbor function"使用 A* 算法优化解决 8-Puzzle