QT/C++类型的异常过载功能情况

Weird overload function situation with QT/C++ types

本文关键字:功能 情况 异常 C++ 类型 QT      更新时间:2023-10-16

我的一位同事创建了一个重载函数,我遇到了一个奇怪的问题,但我们都是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?

这可能与传递参数作为引用并为其提供默认值有关,但我尝试过几种组合,但总是出错。

感谢您抽出时间

这是因为隐式转换的顺序。将字符串文字转换为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++中,临时对象不能绑定到非常量左值引用(第二个重载使用该引用)。但是,Visual Studio允许将其作为扩展。

为什么它决定使用一个重载,它接受一个甚至不属于同一类型的可选参数,而不是使用第二个并尝试将字符串参数用作QVariant?

查看函数签名:

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

第二个过载取一个左值。如果传递const char*,则需要创建一个QVariant右值。

另一方面,有一个函数重载,它采用bool值,这是一个更好的匹配,并被调用。

你还说,如果你这样做:

foo(QString("some_qt_string"));  

第二个被称为。但它甚至不应该编译。您正在将右值传递给采用左值的函数。我不确定你用的是哪种编译器,但那肯定是错误的。设置最大可能的警告级别,看看会发生什么。我希望你不要忽视编译器的警告;)

最简单的解决方案(也许也是最好的)是不要使函数过载。或者至少不要给出默认参数。

第二个重载引用QVariant作为第一个参数。你没有通过QVariant,所以这个过载永远不会被接受。事实上,当您传递QString作为第一个参数时,第二个重载仍然不可行,您应该会得到一个编译器错误。我的猜测是,您正在使用Microsoft VC进行编译,您所观察到的是非标准行为,它允许您获取临时的l值引用。