2014-09-10 56 views
3

我有一个奇怪的问题,我的工作同事所做的一个重载函数,但我们都是C++/QT新手,并且无法找出这样的原因情况。奇怪的过载函数QT/C++类型的情况

的情况如下:

我们有一个重载函数:

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

在我们只有一个可选的布尔参数作为值传递的第一个; 第二个我们有一个QVariant引用,一个可选的qstring引用和一个bool。

什么发生在运行时是当我打电话例如:

foo("some_c++_string"); 

而是采用了一个2号和铸造的字符串的QVariant,它使用的第一个,可能忽略了的说法!奇怪的是,它甚至没有抱怨在编译时不存在foo(char *)的重载,例如! 但是,如果我们这样做:

foo(QString("some_qt_string")); 

它按预期进行第二次重载。

所以,问题是:为什么在这个世界中它决定去接受一个可选的参数,甚至不是相同的类型,而不是使用第二个参数,并试图将字符串参数用作QVariant?

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

感谢您的时间

+3

'QString&arg2 = NULL'这真的编译没有警告或错误? – 2014-09-10 12:07:52

回答

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++中,临时对象不能绑定到非常量左值引用(您的第二次重载需要)。但是,Visual Studio允许将其作为扩展。

+0

实际上,自从开始使用MinGW以来,用C++ 11 但是仍然编译没有错误或者警告...... – RuiDo 2014-09-10 14:17:09

+0

@RuiDo你确定*原型是'QVariant&arg1'而不是' const QVariant&arg1'? – Angew 2014-09-10 14:18:47

+0

我也忘了把它放在这里,但在实际的代码中,我们所有的参数都是const!不知道它是否有所作为: -/ – RuiDo 2014-09-10 14:29:56

3

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

综观功能签名:

FOO(布尔ARG1 = FALSE); foo(QVariant & arg1,QString & arg2 = NULL,bool arg3 = false);

第二次重载取左值。如果您通过const char*,则需要创建一个QVariant右值。

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

你也说,如果你这样做:

foo(QString("some_qt_string")); 

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

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

+0

'QVariant'有一个重载的构造函数,它接受一个'const char *'。 – 2014-09-10 12:09:08

+0

@DDmmmm我的回答是错误的。现在更正了 – 2014-09-10 12:18:52

2

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