是否可以在 C++ 中存储类型?
Is it possible to store a type in C++?
有没有简单的方法来保持变量的类型?
例如,存储在通用容器 std::map<key, std::any> myMap;
中会将值类型转换为 std::any
,并且会忘记初始类型。如果只是以某种方式将类型存储为 std::string
,然后将其与 typeid(someType).name()
进行比较。但是这样恢复类型好像很不方便
自己有一些存储类型的功能似乎很有用:
type my_type = int; // or any other type
my_type data = ...;
std::map<key, std::pair<type, std::any>> myMap;
你应该考虑std::variant。一个变体分配一个隐藏的整数作为每个允许类型的枚举器。
这与解释型语言为您提供的存储类型的能力并不完全相同。但是,存储真正的“任何”类型有多大用处值得怀疑。一个值是不好的,除非你可以对其进行一些操作。为了操作一个值,你必须知道它是什么类型。
举个例子,您可能希望存储值,然后对它们求和。您不想假设值是什么类型,因此您使用存储任何类型的“魔术”任何类型。您的代码现在可以添加 int/float/char/etc。数字和字符串的结果是什么?也许你做大多数解释性语言所做的并将数字转换为字符串。这是你的意思吗?可能是?
然而,int+Widget 的值是多少呢?这还有意义吗?解释性语言会给您带来 运行 时间错误。 C++ 想在编译时给你错误。
如果您使用 Variant,您实际上是在定义一个应该给出合理结果的类型列表,如果任何类型组合的“+”定义不正确,那么代码将不会构建,但另一方面您永远无法获得运行 时间错误。
请参阅下面的代码作为示例。
#include <variant>
#include <vector>
using Value = std::variant<char, unsigned char, short, unsigned short, int, unsigned, float, double>;
Value Sum(std::vector<Value>& values)
{
Value sum = (int)0;
for (const auto& v: values)
sum = std::visit([v](auto c_sum)
{ return std::visit([c_sum](auto c_v)
{
return Value{c_sum+c_v};
}
,v);}
,sum);
return sum;
}
如果你只需要检查std::any
中存储值的当前类型是否是某种类型,你可以使用std::any::type()
:
#include <any>
#include <cassert>
#include <typeinfo>
int main()
{
std::any foo;
assert(foo.type() == typeid(void));
foo = 1;
assert(foo.type() == typeid(int));
foo = 1.23;
assert(foo.type() == typeid(double));
}
有没有简单的方法来保持变量的类型?
例如,存储在通用容器 std::map<key, std::any> myMap;
中会将值类型转换为 std::any
,并且会忘记初始类型。如果只是以某种方式将类型存储为 std::string
,然后将其与 typeid(someType).name()
进行比较。但是这样恢复类型好像很不方便
自己有一些存储类型的功能似乎很有用:
type my_type = int; // or any other type
my_type data = ...;
std::map<key, std::pair<type, std::any>> myMap;
你应该考虑std::variant。一个变体分配一个隐藏的整数作为每个允许类型的枚举器。
这与解释型语言为您提供的存储类型的能力并不完全相同。但是,存储真正的“任何”类型有多大用处值得怀疑。一个值是不好的,除非你可以对其进行一些操作。为了操作一个值,你必须知道它是什么类型。
举个例子,您可能希望存储值,然后对它们求和。您不想假设值是什么类型,因此您使用存储任何类型的“魔术”任何类型。您的代码现在可以添加 int/float/char/etc。数字和字符串的结果是什么?也许你做大多数解释性语言所做的并将数字转换为字符串。这是你的意思吗?可能是? 然而,int+Widget 的值是多少呢?这还有意义吗?解释性语言会给您带来 运行 时间错误。 C++ 想在编译时给你错误。 如果您使用 Variant,您实际上是在定义一个应该给出合理结果的类型列表,如果任何类型组合的“+”定义不正确,那么代码将不会构建,但另一方面您永远无法获得运行 时间错误。 请参阅下面的代码作为示例。
#include <variant>
#include <vector>
using Value = std::variant<char, unsigned char, short, unsigned short, int, unsigned, float, double>;
Value Sum(std::vector<Value>& values)
{
Value sum = (int)0;
for (const auto& v: values)
sum = std::visit([v](auto c_sum)
{ return std::visit([c_sum](auto c_v)
{
return Value{c_sum+c_v};
}
,v);}
,sum);
return sum;
}
如果你只需要检查std::any
中存储值的当前类型是否是某种类型,你可以使用std::any::type()
:
#include <any>
#include <cassert>
#include <typeinfo>
int main()
{
std::any foo;
assert(foo.type() == typeid(void));
foo = 1;
assert(foo.type() == typeid(int));
foo = 1.23;
assert(foo.type() == typeid(double));
}