【问题标题】:how can I store diffrent value types in an array using c++?如何使用 c++ 在数组中存储不同的值类型?
【发布时间】:2011-09-05 00:41:30
【问题描述】:

我想在我的配置类中实现一些功能时遇到问题,我有一些不同类型的值,我想将它们存储在地图中。以前我使用 ExtendedString 类来存储所有数据,并在需要时使用模板函数将它们转换为想要的类型。然后在我的配置类中有一个map<ExtendedString,vector<ExtendedString> > 来将所有键存储在配置文件中。这是我的 ExtendedString 类的样子:

class ExtendedString : public std::string
{
public:
    ExtenedString() : public std::string
    {
    }
    template <class T> ExtenededString(T)
    {
        std::stringstream s;
        *this = s.str();
    }
    template <class T>T as(){
        istringstream s(*this);
        T temp;
        d >> temp;
        return temp;
    }
}

现在我想在加载配置文件时解析所有值,并且还具有在需要时转换为任何可能类型的功能。例如,如果我将某个值解析为 int 并且在我的运行时我需要将该值作为字符串,我希望能够立即将其转换,而且在这种情况下我不喜欢使用 boost,它是我的基类之一,我不想将 boost 链接到我正在开发的每个项目。

【问题讨论】:

  • 我刚买了这把漂亮的电锯。谁能告诉我如何取下防护装置并粘上安全开关?
  • 哈?什么意思?你是说我的问题无关紧要吗?
  • 你不应该从标准库类继承。我在你的 ExtendedString 类中看不到任何需要在类中的东西,只需使用免费函数。
  • @GMan 试图检查您的想法(或至少您的提示引导我的想法)是否可以实施
  • 我的意思是,您充其量只是禁用了防止事故发生的功能。在最坏的情况下,您要求的代码几乎具有人类水平的智能——它还能如何在运行时决定如何转换,例如set&lt;DateAndTime&gt;map&lt;string, Complex&gt;?

标签: c++ arrays class templates generic-type-argument


【解决方案1】:

我建议使用boost::any,因为它听起来就像您正在寻找的那样。但是,如果您真的不想使用它,您也许可以像这样处理它。这可能不是最好的方法(它首先进入我的脑海) - 基本上它将值存储在你最初拥有的类型中,并作为字符串。如果您尝试将get 作为原始类型,它会返回该值,否则,它将使用std::stringstream 尝试并转换它。

注意:这不处理复制/分配,将d_data更改为您选择的共享指针来处理。

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

class ConfigValue
{
    class HolderBase
    {
      protected:
        virtual void writeValueToStream(std::ostream& os) const = 0;

      public: 
        virtual ~HolderBase() { }

        template <class Type>
        Type getAs() const
        {
            std::stringstream ss;
            writeValueToStream(ss);

            Type temp;
            ss >> temp;
            return temp;
        }
    };

    template <class Type>
    class Holder : public HolderBase
    {
        Type d_value;

      protected:
        void writeValueToStream(std::ostream& os) const
        {
            os << d_value;
        }

      public:
        Holder(const Type& value)
        : d_value(value)
        {
            std::ostringstream oss;
            oss << value;
        }

        Type get() const
        {
            return d_value;
        }
    };

    HolderBase *d_data;

  public:
    template <class Type>
    ConfigValue(const Type& value)
    : d_data(new Holder<Type>(value))
    {
    }

    ~ConfigValue()
    {
        delete d_data;
    }

    template <class Type>
    Type get() const
    {
        if (Holder<Type> *holder = dynamic_cast<Holder<Type>*>(d_data))
        {
            return holder->get();
        }
        else
        {
            return d_data->getAs<Type>();
        }
    }
};

int main()
{
    ConfigValue cv = 10;

    std::cout << cv.get<std::string>() << std::endl;

    return 0;
}

【讨论】:

  • 您的实现几乎是我想到的最好的事情,除了您认为可以从每种类型中删除该字符串值吗?顺便说一下,如果类型不匹配, boost::any 不会提供任何转换功能,所以这不是我的解决方案的答案。
  • @Gajet - 我已编辑代码以删除 std::string。现在,如果您尝试将其作为存储数据的类型以外的类型获取,它将调用operator&lt;&lt; 将其写入std::stringstream,然后调用operator&gt;&gt; 将其转换为目标类型。你是这个意思?
  • 不要忘记复制问题,您要么需要为d_data 使用共享指针,要么实现复制构造函数和operator==。否则,在 STL 容器中使用它会遇到问题。
【解决方案2】:

一个经典的解决方案是boost::any,或大量的union。但我认为这两种方法造成的麻烦比它们解决的要多。例如,创建一个 Config 类,每个配置选项都有成员,这有什么问题?

【讨论】:

  • 你能告诉我boost::any是如何实现的吗?
  • @Gajet:boost是开源的,这里是any的实现:boost.org/doc/libs/1_46_1/boost/any.hpp
  • 答案中的“boost::any”是库文档的链接。 “boost::any”本质上是一个大的union,包括原始类型和void*。如果您尝试将一个值存储在不是原始类型的boost::any 中(例如std::string),则该值将使用new 分配,并且指向该值的指针存储在union 中。您必须跟踪您在 boost::any 对象中放入的内容,以便正确地将其转换回来。
  • 我不喜欢内存分配,因为这很慢并且可以避免。而且我不喜欢对象可以包含任何类型的值的概念,程序员负责记住上次存储的内容。
【解决方案3】:

您可以编写一个“值”类,然后为每种值编写子类,而不是将它们全部存储为字符串。

【讨论】:

  • 通过这样做,我需要使用虚拟模板功能(拥有现在的 functino 功能),这是不可能的,如果您知道实现我要求的所有功能的更好方法,请提供您的实现。跨度>
猜你喜欢
  • 1970-01-01
  • 2021-07-11
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 2018-03-28
  • 2023-03-21
相关资源
最近更新 更多