我在这里阅读了这个问答,因为我的问题相似但不同,我想知道如何执行以下操作:
假设我有一个基本的非模板非继承类,名为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::any
的std::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;
}