QT/C++类型的奇怪重载函数情况

3
我是一个有用的助手,可以帮您进行文本翻译。以下是需要翻译的内容:

我在使用一位同事创建的一个重载函数时遇到了奇怪的问题,但我们都是C++/QT新手,不知道出现这种情况的原因。

具体情况如下:

我们有一个重载函数:

foo(bool arg1 = false);
foo(const QVariant &arg1, const QString &arg2 = NULL, bool arg3 = false);

第一个函数只有一个可选的布尔参数作为值;第二个函数有一个QVariant引用、一个可选的QString引用和一个布尔值。

运行时的情况是这样的,例如当我调用:

foo("some_c++_string");

不要使用第二种方法并将字符串转换为QVariant,而是使用第一种方法并忽略参数!奇怪的是,例如在编译时,它甚至不抱怨没有重载foo(char *)的存在!但如果我们执行以下操作:

 foo(QString("some_qt_string"));

正如预期的那样,它进入了第二个重载函数。

那么问题是:为什么它会决定选择接受一个不同类型的可选参数的重载函数,而不是使用第二个重载函数并尝试将字符串参数作为QVariant使用?

这可能与传递引用和给它们默认值有关,但我尝试了几种组合,总是出错。

感谢您的时间。


3
“QString &arg2 = NULL” 这段代码真的能够编译通过而没有警告或错误吗? - BЈовић
3个回答

4
那是因为隐式转换的顺序不同。将字符串字面量转换为bool只需要标准转换顺序:数组到指针的转换(获取const char*)和布尔值转换(获取bool)。
另一方面,将字符串字面量转换为QVariant需要用户定义的转换顺序,因为它涉及一个类QVariant
根据C++11 13.3.3.2/2,
引述如下:
当比较隐式转换序列的基本形式时(如13.3.3.1所定义),
  • 标准转换序列(13.3.3.1.1)优于用户定义的转换序列或省略号转换序列
这意味着第一个重载函数更加严格,因此被选择。
顺便说一下,我敢打赌你正在使用Visual Studio进行构建。否则,这个结构
foo(QString("some_qt_string"));

这段代码可能无法编译通过。原因是QString("some_qt_string")创建了一个临时对象,在标准C++中,临时对象不能绑定到非const左值引用(你的第二个重载函数接受的类型)。然而,Visual Studio允许这种行为作为扩展。


实际上,我从一开始就在使用MinGW和c++11,但是仍然可以编译而没有错误或警告。 - RuiDo
@RuiDo 你确定原型是 QVariant &arg1 而不是 const QVariant &arg1 吗? - Angew is no longer proud of SO
我也忘了在这里放置,但实际代码中我们所有的参数都是const!不知道这是否有所区别 :-/ - RuiDo
嗯,我猜就是这样了!我要试一下:#) - RuiDo
@RuiDo 是的,这确实有很大的区别。临时变量可以绑定到const左值引用,但它们不能绑定到非const左值引用。 - Angew is no longer proud of SO
显示剩余5条评论

3
世界上为什么要选择接受一个可选参数且类型不同的重载函数,而不是使用第二个函数并尝试将字符串参数用作QVariant?
查看函数签名:
foo(bool arg1 = false); foo(QVariant &arg1, QString &arg2 = NULL, bool arg3 = false);
第二个重载接受了lvalue。如果传递const char*,它需要创建QVariant rvalue。
另一方面,有一个函数重载接受bool值,这是更好的匹配,并被调用。
您还说如果这样做:
foo(QString("some_qt_string"));  

第二个被称为。但它甚至不应该编译。您将rvalue传递给需要lvalue的函数。我不确定您使用哪个编译器,但这肯定是错误的。设置最大可能的警告级别并查看会发生什么。希望您不会忽略编译器警告;)

最简单的解决方案(也许是最好的)是不要重载函数。或者至少不要提供默认参数。


QVariant有一个重载的构造函数,可以接受一个const char* - D Drmmr

2
第二个重载函数的第一个参数是一个引用类型的QVariant。由于你没有传递QVariant类型的参数,因此这个重载函数永远不会被调用。实际上,当你将一个QString作为第一个参数传递时,第二个重载函数仍然无法使用,你应该得到一个编译器错误。我猜测你正在使用Microsoft VC编译器,并且你观察到的是一种非标准行为,它允许你获取一个临时变量的左值引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接