【问题标题】:Can one have a vector containing class templates in c++?在 C++ 中可以有一个包含类模板的向量吗?
【发布时间】:2014-12-28 08:53:57
【问题描述】:

我想创建一个结构/类,它至少有一个具有泛型类型的成员变量。 T 可以是从 bitset 到 char 数组的任何内容。让我们称之为“场”。

然后,我想要一个包含多个 Field 对象实例的列表/向量/数组。

这样的数据结构在 C++ 中是否可行?

这就是我的解决方案现在的样子,因为

error C3203: 'Field' : unspecialized class template can't be used as a 模板参数“_Ty”的模板参数,应为真实类型
错误 C2955:“字段”:使用类模板需要模板 参数列表

class Main
{
public:

    template<typename T> class Field {
        public:
            CString name;
            bool state;
            T actualValue;
    };

    vector<Field> m_Message;
};

...

Field field1 = new Field();
field1.actualValue = 1;

Field field2 = new Field();
field2.actualValue = 1.1;

vector<Field> message;

message.push_back(field1);
message.push_back(field2);

这是我第一次在堆栈溢出上发帖,因此对于任何格式错误或问题含糊不清,我深表歉意。

【问题讨论】:

  • 它不是一个模板类,它是一个类模板,也就是构建类的秘诀。但是vector 需要一个完整的类型,而不是一个配方。不过,您可能想看看boost::any
  • vector&lt;Field&lt;???&gt;&gt; m_Message; Main::Field&lt;???&gt; *field1 = new Main::Field&lt;???&gt;();
  • 除了上面提到的问题,你可能想把Main类作为模板,然后在里面使用vector&lt;T&gt;

标签: c++ list class templates vector


【解决方案1】:

不完全是。这就是问题所在,因为我们遍历了向量

for (...:iteraor e....) {
   e->m_Message.actualValue;
}

actualValue 的类型是什么?你可能会说每次都不一样,但 C++ 不是这样工作的,你代码中的每个表达式都有 1 种类型。 (除了模板的东西,但这基本上只是为您输入的每种类型提供了一个新的代码副本)

您可以为所有字段创建一个基类,然后为引用创建一个基类(但不能复制到向量中)。

class FieldBase {
    public:
        CString name;
        bool state;
};
template<typename T>
class Field public: FieldBase
{
 public:
   T actualValue;
};
vector<FieldBase*> m_Message;

然后,您将需要一些消息来发送您正在处理的消息类型。可能是重载的方法。

【讨论】:

    【解决方案2】:

    每个实例化的模板类都有不同的数据类型。在您声明向量时,字段应该已经定义了数据类型,但这里没有。

    我猜,您正在寻找的是一个变体类。像 Qt 这样的一些库提供变体,例如QVariant。

    但是,变体本身不是模板类,也不可能是。变体类通常使用联合和 void 指针来实现。它是动态类型行为的实现。该类型在运行时是动态的。相反,模板在运行时不是动态的。类型在编译时确定,否则编译器要么刹车,要么不生成代码。

    【讨论】:

      【解决方案3】:

      首先,您的示例代码是错误的。正确的版本是

      Field<int> field1 = Field<int>();
      field1.actualValue = 1;
      
      Field<double> field2 = Field<double>();
      field2.actualValue = 1.1;
      

      这里是不是Java,不是吗?


      首先,您应该知道Field&lt;int&gt;Field&lt;double&gt;不同的类型。看看你的例子。

      template <typename T> class Field { ... };
      
      Field<int> field1 = Field<int>();
      field1.actualValue = 1;
      
      Field<double> field2 = Field<double>();
      field2.actualValue = 1.1;
      

      编译器可能会这样想:

      class Field_int { /* int version of Field */ };
      Field_int field1 = Field_int();
      field1.actualValue = 1;
      
      class Field_double { /* double version of Field */ };
      Field_double field1 = Field_double();
      field1.actualValue = 1;
      

      模板实例化就是这样工作的——在编译时。当编译器遇到Field&lt;int&gt; 时,它创建一个新的类从你的模板代码。

      现在您正尝试将不同版本的 Field 推送到 vector

      vector<???> message;
      message.push_back(field1);
      message.push_back(field2);
      

      如您所知,vector 可以保存相同类型的数组。 Field&lt;int&gt;Field&lt;double&gt;同一类型。


      那么,该怎么做呢?由于 C++ 的模板是在编译时运行的,所以我们遇到了这个问题。那么,在runtime期间做呢?

      我建议你使用Boost.Any。它可以在运行时改变它的类型,所以我们可以使用它来代替模板。

      (如果您不了解 Boost,请看一下 - 您会喜欢的。)

      你可以制作Field::actualValueboost::any

      #include <boost/any.hpp>
      
      class Field
      {
          CString name;
          bool state;
          boost::any actualValue;
      };
      
      vector<Field> messages;
      
      Field field1;
      field1.actualValue = 1;
      messages.push_back(field1);
      
      Field field2;
      field1.actualValue = 1.1;
      messages.push_back(field2);
      

      【讨论】:

        【解决方案4】:

        有了足够的元编程,你几乎可以做任何事情。

        在这种情况下,您可能想查看boost::variant,它存储任何一组固定类型中的一个,并为您提供对它的类型安全访问。如果做不到这一点,boost::any 可以保存任何东西之一,但是只有知道您存储在其中的确切类型,您才能获取类型。

        接下来,类型擦除/运行时概念的技术让您可以对您的类型抽象一组有限的操作,并将其存储在任何等价物中,但允许您对数据执行有限的一组操作。

        可能更简单的是发明一个基类,将std::unique_ptrs 存储到它,并存储派生实例。如果需要,使用动态转换来获取特定的子类型。

        如果这些都不起作用,您始终可以运行脚本语言,并使用该语言而不是 C++ 编写代码。许多脚本语言可以嵌入到 C++ 中,而严肃的应用程序经常使用这种嵌入式脚本语言。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-01-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-14
          • 1970-01-01
          相关资源
          最近更新 更多