有没有一种方法可以在不专门化强制转换的情况下转换存储在 QVariant 中的基类型?

Is there a way to convert a base type stored in QVariant without specializing the cast?

让我们考虑这个例子:

QVariant v1(1);
QVariant v2("goofy");
QVariantList list;

list << v1 << v2;

for (const auto& var : list) {
   qdebug() << var;

   // nasty part
   if (var.type == QVariant::Int) {
      int value = var.toInt();

      // do something
   } else if (var.type == QVariant::QString) {
      QString value = var.toString();

      // do something
   }
}

调试函数显示QVariant的内部存储类型:

QVariant(int, 1) QVariant(QString, "goofy") 

有没有办法避免 if 并进行显式转换以访问内部类型?更具体地说,为了获得价值,我希望能够这样写:

auto value = var.ToData();

编辑:由于 QVariant 可以容纳很多类型,您甚至可以在其上添加自定义类型,因此将问题仅限于基本类型就足够了 (int, double, bool, string)

不,这是不可能的。与任何其他变体一样,QVariant 基本上充当联合。除非您知道数据的类型,否则您无法获取它。如果您的假想代码 auto value = var.ToData(); 应该有效,那么 value 的类型必须在编译时可解析 - 但它根本就不是变体。

变体的全部意义在于它使您能够将多种类型存储在一个值中,所有这些都在运行时完成。在内部,它存储它的值的​​类型,但它是一个运行时值 - 所以如果您不确切知道类型,除了进行长切换之外别无他法。

这是可能的,但要付出代价 - QVariant 不会这样做。有两种相关方法:

  1. QVariant 可以在运行时将所有运算符分派给特定类型的运算符,例如添加两个包含整数的 QVariant 可以调用 int operator+(int,int)。之所以没有完成,是因为很难以足够通用的方式完成它,但是如果您有几种类型 - 您当然可以制作自己的类型来完成它。它可以在内部使用 QVariant,但我会谨慎地将它不分青红皂白地暴露为 QVariant。不过,它可以转换为 QVariant,这样您就可以在需要变体的地方传递类型,但不能让它本身成为变体——即使用组合,而不是继承。

  2. QVariant 可以实现模板化类型转发,它会根据您对其执行的操作推断出类型,使用 SFINAE 和模板表达式,并替换 QVariant 上的操作对包含的类型进行操作,没有运行时开销。写出一个足够具体的表达式可以推断出类型,如果它不够具体,那么您就必须提供类型提示——就像在任何具有类型推导的函数式语言中一样。

当您考虑一小部分类型时,任何一种方法都可以很好地工作,但是对于过多的类型 QVariant 必须支持——包括先验未知的用户类型——一般方法有太多限制以至于无法使用。如果不知道您如何处理这些值,则很难说清楚。当给出比 //do something.

更简洁的描述时,可以说更多