2014-10-31 74 views
2

我想创建一个至少有一个具有泛型类型的成员变量的结构/类。 T可以是从bitset到char数组的任何东西。让我们称之为“场”。能有一个包含C++类模板的向量吗?

然后,我想有一个包含多个Field对象实例的list/vector/array。

这样的数据结构在C++中是可能的吗?

这是我的解决方案看起来像现在,它不编译因为

错误C3203:“现场”:非专业化的类模板不能作为模板参数 模板参数'_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); 

这是我第一次发布堆栈溢出,所以我对任何错误的格式化或问题表示抱歉。

+5

它不是一个模板类,它是一个类模板,也就是构建类的配方。但'矢量'期待一个完整的类型,而不是一个配方。不过,你可能想看看'boost :: any'。 – Deduplicator 2014-10-31 23:23:27

+2

'vector > m_Message;'Main :: Field * field1 = new Main :: Field ();' – 101010 2014-10-31 23:25:38

+0

除了上面提到的问题,您可能希望将Main类作为模板,然后使用一个'矢量'里面 – vsoftco 2014-10-31 23:34:48

回答

2

不完全。这里的问题,因为我们遍历向量

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

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

你可以为你所有的Field创建一个基类,然后引用(但不能拷贝到向量)。

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

然后,你需要一些调度你正在处理什么样的消息。重载的方法也许。

1

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

我想,你要找的是一个变体类。一些图书馆如Qt提供了变体,例如的QVariant。

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

0

最重要的是,您的示例代码是错误的。正确的版本将是

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

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

这里的 Java的,不是吗?


首先,你应该知道Field<int>Field<double>不同类型。看看你的例子。

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<int>时,会从您的模板代码中创建一个新类。

现在您试图将不同版本的Field转换为vector。如你所知,vector可以容纳相同类型的数组。 Field<int>Field<double>而不是是同一类型。


那么,该怎么做呢?由于C++的模板在编译期间运行,所以我们遇到了这个问题。那么,在运行时间期间怎么样?我建议你使用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); 
0

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

在这种情况下,您可能想要查看boost::variant,它存储任何一组固定类型中的任何一个,并为您提供类型安全的访问权限。否则,boost::any可以容纳任何东西,但是如果您知道存储在其中的确切类型,则只能获取类型。

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

可能更容易的是创建一个基类,存储std::unique_ptr,并存储派生实例。如果需要,使用动态转换来获取特定的子类型。

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

相关问题