2014-02-21 26 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