0

我在这里阅读此 Q/A ,由于我的问题相似但不同,我想知道如何执行以下操作:

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

class Storage {};

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

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;
}
4

2 回答 2

1

你标记了 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 ?
 }

但问题是现在您在地图中有一个带有“Hotdogs”和“Price”键的元素,但您没有关于值类型的信息。

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

于 2018-03-08T02:45:37.817 回答
0

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

话虽如此,我是在矢量上执行此操作,但该原理也适用于地图。如果您没有构建 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 ex1\n";}
    void operator()(ex2 arg) { std::cout << "got ex2\n";}
};

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 ex1\n";}
    void operator()(ex2 arg) { std::cout << "got ex2\n";}
};

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;
}
于 2018-03-19T16:21:26.527 回答