将多个类型存储到类成员容器中



我在这里阅读了这个问答,因为我的问题相似但不同,我想知道如何执行以下操作:

假设我有一个基本的非模板非继承类,名为Storage

class Storage {};

我希望这个类有一个容器(无序多映射)是我倾向于的地方......这将保留一个变量类型 T 的名称 idstd::string。类本身将不是模板。但是,要添加元素的成员函数将是。要添加的成员函数可能如下所示:

template<T>
void addElement( const std::string& name, T& t );

然后,此函数将填充无序多映射。但是,每次调用此函数时,每种类型都可能不同。所以我的地图看起来像这样:

"Hotdogs", 8  // here 8 is int
"Price",  4.85f // here 4.8f is float.

我将如何使用模板、可变参数,甚至元组、任何或变体来声明这样一个无序多映射......没有类本身是模板?我不喜欢使用标准以外的 boost 或其他库。

我尝试了这样的事情:

class Storage {
private:
template<class T>
typedef std::unorderd_multimap<std::string, T> DataTypes;
template<class... T>
typedef std::unordered_multimap<std::vector<std::string>, std::tuple<T...>> DataTypes;
};

但是我似乎无法正确获取 typedef,以便我可以像这样声明它们:

{
DataTypes mDataTypes;
}

你标记了C++17,所以你可以使用std::any(或者std::variant如果T类型可以是一组有限的和已知的类型)。

存储值很简单。

#include <any>
#include <unordered_map>
class Storage
{
private:
using DataTypes = std::unordered_multimap<std::string, std::any>;
DataTypes mDataTypes;
public:
template <typename T>
void addElement (std::string const & name, T && t)
{ mDataTypes.emplace(name, std::forward<T>(t)); }
};
int main()
{
Storage s;
s.addElement("Hotdogs", 8);
s.addElement("Price", 4.85f);
// but how extract the values ?
}

但问题是,现在您在映射中有一个带有"热狗"和"价格"键的元素,但您没有关于值类型的信息。

因此,您必须以某种方式保存有关第 th 值类型的信息(在具有某些 id 类型和std::anystd::pair中转换值?),以便在需要时提取它。

我已经按照这些思路做了一些事情,实际的解决方案非常特定于您的问题。

话虽如此,我是在向量上执行此操作的,但该原则也适用于地图。 如果您没有构建 API,因此知道将涉及的所有类,则可以使用类似std::variant

以下内容:
#include <variant>
#include <vector>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1n";}
void operator()(ex2 arg) { std::cout << "got ex2n";}
};
int main() {
auto storage = std::vector<storage_t>{};
storage.push_back(ex1{});
storage.push_back(ex2{});
auto op = unspecific_operation{};
for(const auto& content : storage) {
std::visit(op, content);
}
return 0;
}

这将输出:

got ex1
got ex2

如果我没记错的话,使用std::any将启用RTTI,这可能会变得非常昂贵; 可能是错误的。

如果你提供更多关于你真正想用它做什么的细节,我可以给你一个更具体的解决方案。

有关无序列图的示例:

#include <variant>
#include <unordered_map>
#include <string>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1n";}
void operator()(ex2 arg) { std::cout << "got ex2n";}
};
class Storage {
private:
using map_t = std::unordered_multimap<std::string, storage_t>;
map_t data;
public:
Storage() : data{map_t{}}
{}
void addElement(std::string name, storage_t elem) {
data.insert(std::make_pair(name, elem));
}
void doSomething() {
auto op = unspecific_operation{};
for(const auto& content : data) {
std::visit(op, content.second);
}
}
};
int main() {
auto storage = Storage{};
storage.addElement("elem1", ex1{});
storage.addElement("elem2", ex2{});
storage.addElement("elem3", ex1{});
storage.doSomething();
return 0;
}

最新更新