将不同的模板化类存储在一个容器中,而不会丢失有关其类型的信息

Store different templated classes in one container without losing information about it's type

本文关键字:类型 信息 存储 一个      更新时间:2023-10-16

我目前正在处理一个项目,其中我的应用程序的客户端部分必须能够在服务器上创建自定义模板化类。服务器部分必须跟踪这些创建的类,并且必须记住实例化类的类型。问题是,在我的应用程序中大约有 36 种不同的类模板组合是有效的。我目前正在努力跟踪集合中的这些不同类型的类型,而不会丢失有关我的实例的信息。

我目前正在使用这样的东西:

#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};

但我想知道这是要走的路还是有更优雅的方式。在这里,我必须始终切换enum才能从我的存储类中获取完整类型,如下所示:

switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */

提前谢谢。

您可以考虑使用std::variantstd::visit模式

auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);

如果if constexpr看起来很丑,那么您也可以用手卷式访客类代替它。

class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);

正如对问题的评论中所述,这是一种可行的方法,可以帮助:

#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}

看到它在魔杖盒上运行。