【问题标题】:Weird overload function situation with QT/C++ typesQT/C++ 类型的奇怪重载函数情况
【发布时间】:2014-09-10 11:50:11
【问题描述】:

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

这可能与将参数作为参考传递并赋予它们默认值有关,但我尝试了几种组合,但总是出错。

感谢您的宝贵时间

【问题讨论】:

  • QString &arg2 = NULL 这样编译真的没有警告或错误吗?

标签: c++ qt overloading


【解决方案1】:

这是因为隐式转换的顺序。将字符串文字转换为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 你确定原型是QVariant &arg1而不是const QVariant &arg1吗?
  • 我也忘了把它放在这里,但在实际代码中,我们所有的参数都是 const!不知道它是否有所作为:-/
  • 嗯,我想就是这样!我要试试:#)
  • @RuiDo 是的,它非常有所作为。临时对象可以绑定到 const 左值引用,但不能绑定到非 const 左值引用。
【解决方案2】:

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

查看函数签名:

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

第二个重载采用左值。如果您传递const char*,则需要创建一个 QVariant 右值。

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

你也说过如果你这样做:

foo(QString("some_qt_string"));  

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

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

【讨论】:

  • QVariant 有一个采用const char* 的重载构造函数。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2014-05-31
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-29
    • 1970-01-01
    • 2015-08-01
    • 2013-10-14
    相关资源
    最近更新 更多