【问题标题】:QList of user templated defined structs用户模板化定义结构的 QList
【发布时间】:2011-03-31 19:52:44
【问题描述】:

我可以定义一个 QList 以使其包含模板化结构的集合,每个结构都定义在不同的类型上吗??

考虑:

template<typename T>struct AA
{
  T value;
}

我可以声明一个 QList 以便它包含不同的 AA 实例吗? 类似:

struct<int> myIntStruct;
myIntStruct.value = 10;
struct<double> myDobleStruct;
myDoubleStruct = 12.2;

template<typename T>
QList<struct AA<T>> myList;
myList.push_back(myIntStruct);
myList.push_back(myDoubleStruct);

我的意见是 QList 应该包含相同数据类型的实体(即使对于模板化对象),这就是上述操作非法的原因。在那种情况下,我可以在 Qt 中使用什么结构来执行这样的操作??

谢谢,

毗湿奴。

【问题讨论】:

  • 你真正想在这里解决什么问题?
  • 将 JSON 序列化为易于使用的 C++ 结构..

标签: c++ qt templates struct qlist


【解决方案1】:

为什么您希望容器具有不同的对象可能是一个设计缺陷。然而,一些语言支持这一点,例如 Smalltalk,它具有可以包含不同对象类型混合的 Bag Collection 的概念。 Qt 可能已经有某种包容器类,但我不知道它的存在。

这种在单一容器中混合类型的概念在 C++ 的强类型世界中并不适用。变体对象是最接近的东西,即便如此,如果不创建自己的“超级变体”类,您可以通过子类化 QVariant 然后添加一些位来处理您的结构来实现非整数类型。

再次问自己为什么需要此功能?在其他地方实施的更简单的解决方案可能会减少对这种容器的需求。

编辑:QMap&lt;QString, QVariant&gt; 的快速示例,以帮助确定这是否可行。

class SomeObject
{
public:
    SomeObject() // default
        : someInt(0), someDouble(0) {}
    SomeObject(int i, double d) // explicit
        : someInt(i), someDouble(d) {}

    int GetSomeInt() const { return someInt; }
    double GetSomeDouble() const { return someDouble; }

private:
    int someInt;
    double someDouble;
};

// must be outside of namespace
Q_DECLARE_METATYPE(SomeObject)

// then you can do stuff like this:
    QMap<QString, QVariant> mapNameToValue;

    // populate map
    mapNameToValue["UserName"] = "User";
    mapNameToValue["Port"] = 10101;
    mapNameToValue["PI"] = 3.14159265;
    mapNameToValue["DateTime"] = QDateTime::currentDateTime();
    QVariant userValue;
    userValue.setValue(SomeObject(5, 34.7));
    mapNameToValue["SomeObject"] = userValue;

    // read from map
    QString userName = mapNameToValue["UserName"].toString();
    unsigned int port = mapNameToValue["Port"].toUInt();
    double PI = mapNameToValue["PI"].toDouble();
    QDateTime date = mapNameToValue["DateTime"].toDateTime();
    SomeObject myObj = mapNameToValue["SomeObject"].value<SomeObject>();

    int someInt = myObj.GetSomeInt();
    double someDouble = myObj.GetSomeDouble();

QVariant 处理很多类型,它还具有用于用户定义类型的模板方法 setValuevalue&lt;&gt;。如上所示,您必须使用Q_DECLARE_METATYPE 宏将其注册到QMetaType 并提供默认构造函数以防value&lt;&gt; 转换失败。它不支持某些比较运算符,所以我会制作自己的 QVariantQMetaType 版本,以便与所需的任何额外类型很好地配合,因此感觉更加一致。

【讨论】:

  • 在我的代码中,我希望有一个框架可以将 JSON 文件读入非常简单、易于使用的结构。在 JSON 中,无法预测下一个要读取的名称/值对的类型,因此需要在单个数组或结构中使用多种类型。
  • 啊,所以你不想定义一个具有每种类型的结构,因为那会很浪费。如果它始终是一个键/值对,那么QMap&lt;QString, QVariant&gt; 可能会为您工作。如果您对同一个键有多个值,那么您将使用 QMultiMap
【解决方案2】:

模板类不是一个类,它是一个模板。您可以使用它来实例化完全不相关的类,例如AA&lt;int&gt;AA&lt;double&gt;

为了获得您正在寻找的功能 - 将不相关的类添加到容器中 - 您需要一个专门支持添加此类不相关实例的容器,或者您需要将对象包装在例如boost::variant

【讨论】:

  • 我不认为我可以在我的项目中使用 boost,Qt 中有没有这样的包装器??
  • QVariant 适用于 intdouble 等类型
  • 你可以在 QT 中使用 boost ...但你不应该这样做,因为 QT 有很多类似的功能。
【解决方案3】:

你说得对,你通常不能在同一个容器中拥有非同质类型。

您可以使用(智能)指针容器boost::anyboost::variant 来解决这个问题,我相信还有其他机制。

【讨论】:

    【解决方案4】:

    我相信MyTemplateClass&lt;int&gt;MyTemplateClass&lt;double&gt; 被认为是独立的数据类型,因此您不能同时拥有包含这两种类型的QList。

    不过,您有很多选择。如果您只是存储简单的数据类型,请查看QVariant。它是一个单一的类类型,但它使用联合来保存其中的各种数据类型。而且它是内置的,因为您已经在使用 Qt!

    如果您尝试存储更复杂的内容,多态类可能是您的最佳选择。然后你可以有一个MyBaseType*s 的QList,并且你需要从列表中调用的所有函数都是virtual。您甚至可以让 MyBaseType 继承自 QVariant,这样数据存储就会为您处理好。

    希望这会有所帮助!

    【讨论】:

    • QVariant 可以存储非 QObject 吗?即它可以像我上面使用的那样存储结构实例(即 myIntStruct 和 myDoubleStruct)吗??
    • It seems that it can. 我自己从未使用过这个,但它看起来相当简单。你需要在你的类上有一些默认的构造函数,你需要使用this macro...但是正如我所说,我不熟悉细节 - 祝你好运!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    相关资源
    最近更新 更多