用户模板化定义结构的 QList

发布于 2024-10-28 23:36:47 字数 573 浏览 5 评论 0原文

我可以定义一个 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 中使用什么结构来执行类似的操作?

谢谢,

毗湿奴。

Can I define a QList such that it holds a collection of templated structs, with each struct defined on different type ??

Consider:

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

Can I declare a QList such that it holds different instances of AA ??
something like:

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);

My Opinion is that the QList should contain entities of same datatype (even for a templated objects) and that's why the above operation is illegal. In that case what structure can I use in Qt to do an operation like that ??

Thanks,

Vishnu.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

素衣风尘叹 2024-11-04 23:36:47

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

这种在单个容器中混合类型的概念在 C++ 的强类型世界中不太适用。变体对象是最接近的东西,即使这样,也不适用于非整数类型,而不需要创建自己的“超级变体”类,您可以通过子类化 QVariant 然后添加一些位来处理您的结构来完成。

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

编辑:QMap 的快速示例,以帮助确定这是否可行。

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>>。如上面简要所示,您必须使用 Q_DECLARE_METATYPE 宏将其注册到 QMetaType 并提供默认构造函数,以防 value 转换失败。它不支持某些比较运算符,因此我会制作自己的 QVariantQMetaType 版本,以便与所需的任何额外类型很好地配合,因此感觉更加一致。

Why you would want a container to have dissimilar objects is probably a design flaw. However some languages support this such as Smalltalk which has the concept of a Bag Collection that can contain a mix of different object types. Qt may have some sort of bag container class already but I am unaware of it's existence.

This concept of mixed types in a single container does not work so well in the strongly typed world of C++. Variant objects are the closest thing and even then not for non integral types without making your own "super variant" class which you could do by subclassing QVariant then adding some bits to handle your structs.

Again ask yourself the question why do you need this functionality? A simpler solution implemented elsewhere will probably alleviate the need for such a container.

Edit: Quickie example of QMap<QString, QVariant> to help determine if that would work.

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 handles a lot of types it also has template methods setValue and value<> for user defined types. As shown briefly above you have to use Q_DECLARE_METATYPE macro to register it with QMetaType and provide a default constructor in case value<> conversion fails. It won't support certain comparison operators so I would make my own version of QVariant and QMetaType to play nice with any extra types needed so it feels more consistent.

暗藏城府 2024-11-04 23:36:47

模板类不是一个类,它是一个模板。您可以使用它来实例化完全不相关的类,例如AAAA

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

A template class isn't a class, it's a template. You can use it to instantiate completely unrelated classes, such as AA<int> and AA<double>.

In order to get the functionality you're looking for - adding unrelated classes to a container - you need either a container that specifically supports adding such unrelated instances, or you need to wrap your objects in e.g. boost::variant

森林散布 2024-11-04 23:36:47

你是对的,同一个容器中通常不能有非同质类型。

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

You're right that you can't generally have non-homogeneous types in the same container.

You can get around that with containers of (smart) pointers, boost::any, boost::variant, and I'm sure other mechanisms.

浪推晚风 2024-11-04 23:36:47

我相信 MyTemplateClassMyTemplateClass 被视为单独的数据类型,因此您不能拥有同时包含这两种类型的 QList。

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

如果您想存储更复杂的东西,多态类可能是正确的选择。然后,您可以拥有一个 MyBaseType* 的 QList,并将需要从列表中调用的所有函数设为 virtual。您甚至可以使 MyBaseType 继承自 QVariant,以便为您处理数据存储。

希望这有帮助!

I believe that MyTemplateClass<int> and MyTemplateClass<double> are considered to be separate data types, so you can't have a QList containing both types at once.

You've got options, though. If you're just storing simple data types, check out QVariant. It's a single class type, but it uses unions to hold a variety of data types inside it. And it's built-in, since you're already using Qt!

If you're trying to store more complicated things, polymorphic classes are probably the way to go. Then you can have a QList of MyBaseType*s, and have all the functions you need to call from the list be virtual. You can even make MyBaseType inherit from QVariant, so the data storage is taken care of for you.

Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文