2014-02-21 30 views
0

我有這樣的代碼:簡單的運算符重載不起作用

template <typename T> 
class EasyPtr { 
    T* data; 
    public: 
    EasyPtr(T* data): data(data){} 
    EasyPtr(const EasyPtr<T>&)=delete; 
    EasyPtr(EasyPtr<T>&&) = delete; 
    ~EasyPtr(){ 
     delete data; 
    } 
    operator T*(){ 
     return data; 
    } 
    EasyPtr & operator = (T* data) { 
     this -> data = data; 
    } 
    T& operator *() { 
     return *data; 
    } 
    T& operator [](size_t pos) { 
     return data[pos]; 
    } 
}; 
int main(){ 
    EasyPtr<int> p = new int[10]; 
    return 0; 
} 

令人驚訝的是給了錯誤:

In file included from easy_ptr_test.cpp:1:0: 
./easy_ptr.hpp:23:20: error: declaration of ‘operator[]’ as non-function 
./easy_ptr.hpp:23:18: error: expected ‘;’ at end of member declaration 
./easy_ptr.hpp:23:27: error: expected ‘)’ before ‘pos’ 
easy_ptr_test.cpp: In function ‘int main()’: 
easy_ptr_test.cpp:4:32: error: use of deleted function ‘EasyPtr<T>::EasyPtr(EasyPtr<T>&&) [with T = int]’ 
In file included from easy_ptr_test.cpp:1:0: 
./easy_ptr.hpp:10:5: error: declared here 

這顯然是一個函數聲明......不明白爲什麼。也許在某個地方有一個愚蠢的錯誤。

+1

您的賦值運算符缺少返回語句。 –

+0

@ K-ballo多數民衆贊成在一個問題......但它給我在修復它後出現同樣的錯誤 – texasbruce

+1

該行主要隱含地構建了一個臨時的'EasyPtr '在右側。該臨時可以移動到「p」中。臨時移動到「p」的行爲甚至可以被忽略,但爲了實現這一點,移動構造函數仍然必須可訪問,因此也是錯誤。如果將其更改爲'EasyPtr p(new int [10])',它應該可以工作。 – 0x499602D2

回答

2

size_t類型在cstddef標題中定義,因此您在使用它之前應該使用#include。這應該擺脫圍繞您的operator[]聲明的錯誤。

main中的錯誤是由於複製初始化的原因而產生的。當你做

EasyPtr<int> p = x; 

要執行副本初始化。如果x的類型爲EasyPtr<int>,或者是其cv合格版本或其衍生類之一,則此初始化的效果僅僅是調用EasyPtr<int>的複製或移動構造函數(而不是複製分配或移動-assignment操作者!)如果x是不同類型的,那麼x首先用於構造一個臨時EasyPtr<int>對象,然後複製或移動的EasyPtr<int>構造函數被調用,以複製或移動該臨時對象到p。由於編譯器想要調用移動構造函數,但您已將其刪除,所以出現錯誤。 (再次,複製分配和移動賦值操作符是而不是。)

解決方案:

1)顯式定義轉移構造

EasyPtr(EasyPtr<T>&& other): data(other.data) { 
    other.data = nullptr; 
} 

2)明確默認情況下,移動構造函數(你可能不希望爲這個特殊的班級做到這一點,是因爲它」會導致雙重自由,但這種方法是出於完整性的緣故)

EasyPtr(EasyPtr<T>&&) = default; 

3)使用直接初始化,而不是複製初始化

EasyPtr<int> p {new int[10]}; 

最後一個選項可能是你想要的選項,因爲它看起來像你不希望你的對象被複制或移動。在這種情況下,複製初始化不會起作用,所以你應該聲明轉換構造函數explicit,這樣錯誤信息就不會混淆了。

explicit EasyPtr(T* data): data(data){} 
+0

+1更多的解釋比我的。 – 0x499602D2

1
EasyPtr<int> p = new int[10]; 

該行主要隱含地在右側構建了一個臨時EasyPtr<int>。從概念上講,它看起來像這樣:

EasyPtr<int> p = EasyPtr<int>(new int[10]); 

這個臨時的可以移動到p。如果你的編譯器實現copy-elision,那麼臨時移動到p甚至可以被忽略;但爲了實現這一點,移動構造函數仍然必須可訪問。因爲移動構造函數聲明爲delete'd,您會收到錯誤。如果將其更改爲EasyPtr<int> p(new int[10]),則該錯誤應該消失,因爲您不再從另一個EasyPtr實例構造p