2014-09-10 55 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值引用。