我对可变参数模板和打包参数等等都很陌生。 我想在我的程序中拥有一个“实体组件系统”,在尝试向实体添加组件时,我意识到我的尝试有一个重大缺陷。
无论如何,这是我失败的尝试。
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);
我希望实现能够以某种方式工作..必须对其进行哪些更改?
最佳答案
您可以使用以下内容(全部在编译时):
-
std::is_same
检查两种类型是否相同(需要#include <type_traits>
)。 -
if constexpr
基于它进行分支(c++17 及以上)。 -
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);
}
注释:
- 我使用了标准
nullptr
推荐代替NULL
. - 使用简单的
static_assert(false, ...)
不保证能够按照 @RemyLebeau 的评论 ( How can I create a type-dependent expression that is always false? ) 中提到的原因工作。
该文章中建议的解决方案之一是使用static_assert(!sizeof(T), ...)
假设 sizeof 永远不为 0。本文还提出了一个稍微复杂的解决方案来避免这种假设。
关于c++ - 如何解压可变参数模板,以便初始化相应的成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76233054/