有没有一种方法可以在不专门化强制转换的情况下转换存储在 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
不会这样做。有两种相关方法:
QVariant
可以在运行时将所有运算符分派给特定类型的运算符,例如添加两个包含整数的 QVariant
可以调用 int operator+(int,int)
。之所以没有完成,是因为很难以足够通用的方式完成它,但是如果您有几种类型 - 您当然可以制作自己的类型来完成它。它可以在内部使用 QVariant
,但我会谨慎地将它不分青红皂白地暴露为 QVariant
。不过,它可以转换为 QVariant
,这样您就可以在需要变体的地方传递类型,但不能让它本身成为变体——即使用组合,而不是继承。
QVariant
可以实现模板化类型转发,它会根据您对其执行的操作推断出类型,使用 SFINAE 和模板表达式,并替换 QVariant
上的操作对包含的类型进行操作,没有运行时开销。写出一个足够具体的表达式可以推断出类型,如果它不够具体,那么您就必须提供类型提示——就像在任何具有类型推导的函数式语言中一样。
当您考虑一小部分类型时,任何一种方法都可以很好地工作,但是对于过多的类型 QVariant
必须支持——包括先验未知的用户类型——一般方法有太多限制以至于无法使用。如果不知道您如何处理这些值,则很难说清楚。当给出比 //do something
.
更简洁的描述时,可以说更多
让我们考虑这个例子:
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
不会这样做。有两种相关方法:
QVariant
可以在运行时将所有运算符分派给特定类型的运算符,例如添加两个包含整数的QVariant
可以调用int operator+(int,int)
。之所以没有完成,是因为很难以足够通用的方式完成它,但是如果您有几种类型 - 您当然可以制作自己的类型来完成它。它可以在内部使用QVariant
,但我会谨慎地将它不分青红皂白地暴露为QVariant
。不过,它可以转换为QVariant
,这样您就可以在需要变体的地方传递类型,但不能让它本身成为变体——即使用组合,而不是继承。QVariant
可以实现模板化类型转发,它会根据您对其执行的操作推断出类型,使用 SFINAE 和模板表达式,并替换QVariant
上的操作对包含的类型进行操作,没有运行时开销。写出一个足够具体的表达式可以推断出类型,如果它不够具体,那么您就必须提供类型提示——就像在任何具有类型推导的函数式语言中一样。
当您考虑一小部分类型时,任何一种方法都可以很好地工作,但是对于过多的类型 QVariant
必须支持——包括先验未知的用户类型——一般方法有太多限制以至于无法使用。如果不知道您如何处理这些值,则很难说清楚。当给出比 //do something
.