【问题标题】:Storing attributes in a STL container?在 STL 容器中存储属性?
【发布时间】:2010-11-02 23:31:48
【问题描述】:

假设我有一个名为 generic_pair 的类,格式如下:

template < typename K, typename V >
struct generic_pair{
  K key;
  V value;
};

现在,问题是我希望能够将这些 generic_pairs 存储在一个 STL 容器中但是容器中的所有 都不是同一类型。例如,一些元素可能是 而其他元素可能是 等等。问题是我们如何才能做到这一点?

我的第一个想法是使用“标签”来创建封装类型的层次结构,并使用泛型类型声明容器,但实际元素具有继承类型。例如,

struct base_type{
  typedef void type;
};

struct int_type: base_type{
  typedef int type;
}

struct string_type: base_type{
  typedef std::string type;
}

/// and so on establish a type hierarchy as necessary and then...

std::vector < generic_pair < base_type, base_type > > vec;

我敢打赌,有更好、更正确的方法吗?任何想法,方向表示赞赏。如果您在 MPL 或其他地方看到过类似的实现或相关工具/技术,那也很有帮助。 (我试图避免使用宏)

【问题讨论】:

  • 与“我怎样才能将非多态的东西硬塞到容器中”的问题一样,如果可能的话,你需要弄清楚你将如何实际使用容器。如果您遍历这些项目,您希望能够对它们做什么?
  • @Oli:假设基于键和/或值的类型,我想将它们打印出来或序列化到磁盘。现在,你会如何“拔掉”它?

标签: c++ templates boost-mpl


【解决方案1】:

如果预先确定了类型集,您可以使用Boost.Variant。如果没有,那么Boost.Any 可能会成功。

【讨论】:

  • Indded,否则boost::any
  • 啊,boost::any 是一只熟悉的野兽。将研究这两个建议。谢谢。
【解决方案2】:

根据您的问题和随后澄清的问题,以下内容可以满足您的要求:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

// All class-template instantiations derive from this
struct AbstractPair
{
    virtual std::string serialize() const = 0;
};

template<typename K, typename V>
struct Pair : public AbstractPair
{
public:
    Pair(K key, V value) : key(key), value(value) {}

    std::string serialize() const
    {
        std::stringstream ss;
        ss << "Key: " << key << ", Value: " << value;
        return ss.str();
    }
    K key;
    V value;
};


int main()
{
    // Vector of pointers-to-abstract-base
    std::vector<AbstractPair *> v;

    // Create derived objects (instantiate class template)
    AbstractPair *p1 = new Pair<int,int>(5,10);
    AbstractPair *p2 = new Pair<float,std::string>(3.2f, "Hello");

    // Valid, and type-safe
    v.push_back(p1);
    v.push_back(p2);

    // Demonstrate polymorphism
    for(std::vector<AbstractPair *>::iterator it = v.begin(); it != v.end(); ++it)
    {
        std::cout << (*it)->serialize() << std::endl;
    }

    // Boilerplate cleanup
    delete p1;
    delete p2;
    return 0;
}

}

【讨论】:

  • 打败了我......好吧...... :)
  • @kvs:嗯,你应该在你的问题中提到这种限制!另外:为什么不呢? (上面的概念验证代码可以用智能指针更干净地完成)
  • 我认为示例和问题暗示了具有值语义的容器。使用指针和多态将任何类型硬塞到 STL 容器中很容易。我正在寻找适当的值语义和编译时类型检查等(参见 boost::variant 文档,例如,指针和多态性可能不适合的原因列表)。我正在编写一个库而不是一个程序。
  • @kvs:您的问题根本没有真正暗示这一点,但足够公平。我上面的“解决方案”没有遇到 boost 变体文档中描述的问题;它是类型安全的,并且不涉及向下转换(至少,不是像您所说的那样解决问题!)。如果您可以编辑您的问题以描述可能存在问题的原因,那么我可以进一步回复......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
  • 2011-02-12
  • 2012-12-01
  • 1970-01-01
相关资源
最近更新 更多