2016-02-02 62 views
1

當我在寫關於基本運算符重載一些代碼。我來到這個代碼片段,ISO C++說,這些都是不明確的,操作符重載

struct MyInt { 
    public: 
    MyInt() : data() { }; 

    MyInt(int val) : data(val) { } 

    MyInt& operator++() { 
     ++data; 

     return (*this); 
    } 

    MyInt operator++(int) { 
     MyInt copy = *this; 
     ++data; 

     return copy; 
    } 

    MyInt& operator+=(const MyInt& rhs) { 
     data += rhs.data; 
     return *this; 
    } 

    MyInt operator+(const MyInt& rhs) const { 
     MyInt copy = *this; 
     copy += rhs; 

     return copy; 
    } 

    int data; 
}; 

這些都是正常,直到我的類

MyInt operator+(const MyInt& lhs, const MyInt& rhs) 
{ 
    MyInt copy = lhs; 
    copy.data += rhs.data; 

    return copy; 
} 

的聲明之後加入這個權利有了這個主declartion

int main() { 
    MyInt mi = 10; 
    MyInt mi2 = 11; 
    MyInt mi3 = mi++ + ++mi2; 

    mi3 += mi2; 
} 

當我嘗試編制,G ++我

warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: 
    MyInt mi3 = mi++ + ++mi2; 
         ^
note: candidate 1: MyInt operator+(const MyInt&, const MyInt&) 
MyInt operator+(const MyInt& lhs, const MyInt& rhs) 
    ^
note: candidate 2: MyInt MyInt::operator+(const MyInt&) const 
    MyInt operator+(const MyInt& rhs) const { 
拋出此警告

從我見過的其他問題來看,它們都是錯誤而不是警告。所以我不確定爲什麼它的代碼仍然有效。希望有人能向我解釋爲什麼會發生這種情況。

在此先感謝。

+4

@Drop這是什麼UB? 'MyInt mi3 = mi ++ + ++ mi2;'是三個不同的變量,所以沒有UB。 – NathanOliver

+0

這裏沒有真正的問題。 「他們爲什麼不明確?」 「爲什麼g ++將此作爲警告並仍然創建二進制文件?」 –

+0

@NathanOliver我認爲這是因爲左邊的後綴意味着'const&'被轉換爲一個臨時值......但這似乎排除了lhs + rhs定義是一個合格的重載,所以我'我不確定除了「ISO是這麼說的」之外,還有什麼是「模棱兩可的」。 [另外,我上面的評論回覆了一個現在被刪除的評論,稱這是一個值得采訪的UB例子] –

回答

7

有一個成員函數operator+(const MyInt&) const可稱爲是這樣的:

MyInt m1; 
MyInt m2; 
m1 + m2; 

還有一個免費的功能operator+(const MyInt&, const MyInt&),可稱爲是這樣的:

MyInt m1; 
MyInt m2; 
m1 + m2; 

這就是爲什麼編譯器抱怨:語言定義說,沒有辦法決定使用哪一個。挑一個或另一個。

通常的慣例是隻自由的功能,並通過調用operator+=實現它。

該警告是告訴你,接受該代碼是gcc的一個擴展。形式上,編譯器不需要拒絕編譯錯誤的代碼。唯一的要求是他們發佈了一個gcc做的診斷。完成之後,可以繼續以某種編譯器認爲合理的方式編譯代碼。依賴這種擴展的代碼是不可移植的。

+0

你碰巧知道在這種情況下g ++選擇調用哪個超載?我可以看到兩者的論點。 –

+0

根據user2079303的答案添加-pedantic後,它會變成錯誤,而不是由於模糊的重載。謝謝你詳細解釋這個問題! – Colorfusion

+0

@MarkB - 我不知道,但是從編譯器的消息中,我猜測它是自由函數,因爲那是「第一個最糟糕的轉換比第二個最糟糕的轉換更好」的那個。 –

2

從我看到的其他問題來看,它們都是錯誤而不是警告。

這可能是因爲準時的程序員告訴他們的編譯器不接受非標準的兼容程序,這些程序可能會跳過。例如,他們會使用GNU編譯器時使用-pedantic或更嚴格-pedantic-errors選項。

所以,我真的不知道爲什麼它的代碼仍然可以工作。

如果你不告訴你的編譯器不接受非標準的代碼,那麼它可能會接受它,如果他們支持它作爲語言的擴展。在這種情況下,標準說重載同樣不明確,程序不合格,但編譯器可能會比較樂觀,並猜測你可能打算使用的重載,儘管該標準說了什麼。

您顯示的代碼恰好在不使用任何選項的情況下編譯時僅使用g ++中的警告,但使用-pedantic選項時,這些警告將成爲錯誤。通常-pedantic只會在使用語言擴展時添加警告,但在這種情況下,它似乎會將警告提示爲錯誤。

+0

添加迂腐之後,由於含糊不清的超載,它變成了你所說的錯誤,現在對我來說是有意義的。感謝您的幫助! – Colorfusion