关联标准::元组容器

associative std::tuple container

本文关键字:元组 关联 标准      更新时间:2023-10-16

是否可以定义(以简单的方式,可能重用std容器)一个"关联std::tuple",或者换句话说说一个"variadiac std::map"。

像这样的东西(这个接口只是为了解释,欢迎其他可能的接口):

AssociativeTuple<std::string> at;    // std:string is the key type
at.insert<float>("my_float", 3.14);  // 1.
at.insert<int>("my_int", 42);
at.insert<bool>("my_bool", true);
at.insert<int>("xyz", 0);
at.insert<std::string>("my_string", "hello world!");
assert(get(at, "my_float") == 3.14);  // 2.
assert(get(at, "my_int") == 42);
assert(at["my_string"] == "hello world!");  // 3.
assert(std::is_same<at.type_of("my_float")::type, float>)  // 4.
for (auto it : at) { std::cout << it.first << " = " << it.second; }  // 5.

其他理想的约束:

  1. 值/键集仅在运行时已知。但是在编译时,用户知道(值的类型)和键之间的关系。例如,用户在编译时知道"my_float"将是一个float。换句话说,键的可能集合是固定的,并且与键对应的值的类型在编译时是已知的。编译时不知道的是"如果"将在容器中插入一个键。当然,映射值的值在编译时是未知的。
  2. 访问性能,get应该很快
  3. 用户不必记住与键关联的类型

我真正的问题只是 float/int/bool 类型的值(我正在做的是将所有内容存储在std::map<std::string, float>中并在必要时转换为int),但通用解决方案是可取的。在我的真实情况下,密钥总是std::string

您可能是指具有多态值的映射。对于多态值,您可以使用boost::any或更好的boost::variant<> .例如:

typedef boost::variant<int, double, std::string> MyVariant;
typedef std::map<std::string, MyVariant> MyPolymorphicMap;

这个怎么样?(注意:这些值不是元组;每个键有一个值)。

template<class K> using AnyMap = std::map<K, boost::any>;
AnyMap map;
map["test1"] = 124;
map["test2"] = std::string{ "some text" };
auto value = boost::any_cast<int>(map["test1"]);

是的,这可以使用变体(那里有很多实现)或通常的某种包装器,无论是基于联合(在您的情况下首选方式)还是从公共基类派生。

对于像get(at, "my_int") == 42这样的事情,你必须重载相等运算符布尔operator==(Variant&, int)但这应该也不是问题。

你不能做像std::is_same<at.type_of("my_float")::type, float>这样的事情,因为is_same是一个编译时表达式,但类型(你正在寻找)只在运行时是已知的。但是,您仍然可以定义执行该检查的运行时函数。

但是:如果 - 在您的特定情况下 - 您只需要intfloat并且您不需要硬性内存(使用字符串作为键似乎表明了这一点),那么我只是使用double因为它可以表示您可能想要存储的任何数字。

另一种可能性是使用两个单独的数据结构(一个用于 int,一个用于浮点数)。如有必要,您还可以在这些周围构建一个 rwarpper,以使它们看起来像一个。使用多个数据结构可能特别有意义,前提是您的编程逻辑始终知道与键关联的类型,然后再执行查找。