我的一个同事做了一个重载函数,我遇到了一个奇怪的问题,但我们都是C ++ / QT新手,无法弄清楚出现这种情况的原因。
情况如下:
我们有一个重载功能:
foo(bool arg1 = false);
foo(const QVariant &arg1, const QString &arg2 = NULL, bool arg3 = false);
在第一个上,我们只有一个可选的bool参数作为值传递; 在第二个,我们有一个QVariant引用,一个可选的qstring引用和一个bool。
在运行时发生的事情是我打电话的时候:
foo("some_c++_string");
而不是使用第二个并将字符串转换为QVariant,它使用第一个并且可能忽略参数!奇怪的是,它甚至没有抱怨在编译时没有为foo(char *)存在重载! 但是,如果我们这样做:
foo(QString("some_qt_string"));
按预期进入第二次重载。
所以,问题是:为什么在世界上它决定采用一个接受一个可选参数的重载而不是使用第二个并尝试将字符串参数用作QVariant?< / p>
它可能与将参数作为参考传递并给出默认值有关,但我尝试了几种组合并且总是出错。
感谢您的时间
答案 0 :(得分: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允许将其作为扩展名。
答案 1 :(得分:3)
为什么在世界上它决定采用一个接受一个可选参数的重载,而不是使用第二个并尝试将字符串参数用作QVariant?
查看函数签名:
foo(bool arg1 = false); foo(QVariant&amp; arg1,QString&amp; arg2 = NULL,bool arg3 = false);
第二次重载采用左值。如果您传递const char*
,则需要创建QVariant rvalue。
另一方面,有一个函数重载,它接受一个bool值,这是一个更好的匹配,并被调用。
你还说如果你这样做:
foo(QString("some_qt_string"));
第二个叫。但它甚至不应该编译。您正在将rvalue传递给一个带左值的函数。我不确定你使用哪种编译器,但这肯定是错误的。放置最大可能的警告级别,看看会发生什么。我希望你不要忽视编译器警告;)
最简单的解决方案(也许是最好的)不会使功能过载。或者至少不提供默认参数。
答案 2 :(得分:2)
第二个重载通过引用获取QVariant
作为它的第一个参数。你没有传递QVariant
,所以永远不会超载。实际上,当您传递QString
作为第一个参数时,第二个重载仍然不可行,您应该得到编译器错误。我的猜测是你正在使用Microsoft VC进行编译,你所观察到的是非标准行为,它允许你对临时值进行l值引用。