2012-11-05 171 views
3

我想了解更多关于模板的知识,并遇到了一个我似乎无法解决的问题。目前下面的课程正常工作。初始化嵌套模板

#include <iostream> 
#include <vector> 
#include <cstring> 
using namespace std; 

template <class T, int s> 
class myArray{ 
public: 
    T* data; 
    inline T& operator[](const int i){return data[i];} 
    myArray(){ 
     data=new T[s]; 
    } 
    myArray(const myArray& other){ 
     data=new T[s]; 
     copy(other.data,other.data+s,data); 
    } 
    myArray& operator=(const myArray& other){ 
     data=new T[s]; 
     copy(other.data,other.data+s,data); 
     return *this; 
    } 
    ~myArray(){delete [] data;} 
}; 

如果我使用它:

myArray<myArray<myArray<int,10>,20>,30> a; 

现在是我可以与正常阵列括号例如访问30x20x10阵列一个[5] [5] [5]。我想添加一个功能,这样我可以这样写:

myArray<myArray<myArray<int,10>,20>,30> a(10); 

并初始化所有条目,以10例。我无法解决如何做到这一点。据我所知,myArray的每一层都是使用默认构造函数构造的。如果我改变这对类似:

myArray(int n=0){ 
     data=new T[s]; 
     fill(data,data+s,n); //T might not be of type int so this could fail. 
} 

我认为,当数据不是int类型的(即在尺寸> 1的任何阵列上)这个失败,但是事实并非如此。它适用于数组为平方的情况,但如果不是,则某些条目不会设置为10.有人知道标准向量类如何实现此目的吗?任何帮助将是惊人的。谢谢!

+3

你的赋值运算符不清理旧数据。 – Puppy

回答

1

std :: vector在内存块上使用放置新内容。它在第二行代码中分配内存后构建数据。

这种技术也适用于你。小心放置新的,因为它需要你手动调用析构函数。

这里是没有放置半称职的航路新:

template<typename U> 
explicit MyArray(U const& constructFromAnythingElse) 
{ 
    AllocateSpace(N); // write this, just allocates space 
    for (int i = 0; i < N; ++i) 
    { 
    Element(i) = T(constructFromAnythingElse); 
    } 
} 

与放置新的,你必须先分配内存,然后构造就地,然后记得在最后摧毁每一个元素。

与放置新路线相比,以上是半路由,因为我们先构建每个元素,然后构建另一个元素,并使用operator=来覆盖它。

通过使它成为任意类型的模板构造函数,我们不依赖多次转换来将多个级别向下放入数组中。天真的版本(在你使用T const &时)不起作用,因为要构造一个T数组数组,数组最后一个需要一个T数组数组作为参数,它需要一个T数组作为争论,预计T - 有太多的用户定义的建设水平在那里进行。

利用上述模板的构造,T的阵列的阵列的阵列可以接受任何类型的构造器。就像T的数组一样,T的数组也是如此。最后,无论您构造T数组最外面的数组,都会传递T,并且如果它不喜欢它,则会出现编译器错误消息几乎完全不可读。

3

那么,尝试这样的事情:

myArray() 
: data(new T[s]())  // value-initialization! 
{ 
} 

myArray(T const & val) 
: data(new T[s])  // default-initialization suffices 
{ 
    std::fill(data, data + s, val); 
} 

如果你到可变参数模板,你可以煮了涉及variadically充满初始化列表一些更怪诞的,但我认为我们已经做了足够的学习一周。

注意,在使用new的根本缺陷:任何一个版本需要您的T类可以在一些“默认”状态被实例化,这是分配,即使我们从未要求在第二个版本的默认状态。这就是为什么“真实”库分离内存分配和对象构造的原因,除非它的放置版本,否则你永远不会看到new表达式。

+0

谢谢。我做到了,当'MyArrays'有2个或更少的尺寸时,它就可以工作。对于较大的数组,我得到'没有匹配函数调用'myArray ,3>,3> :: myArray(int)''。这里是我的新的代码,如果任何人都有机会拿一览:[http://ideone.com/PxJgo6](http://ideone.com/PxJgo6)谢谢! – Jack

1

制作专业化含有其它阵列的阵列。要做到这一点,你需要一些常见的实现类一般和专门MYARRAY使用:

共同实施(我做了一些修复你 - 看!评论):

template <class T, int s> 
class myArrayImpl { 
public: 
    T* data; 
    T& operator[](int i){return data[i];} //!!! const before int not needed 
    const T& operator[](int i) const {return data[i];} //!!! was missing 
    myArrayImpl(){ 
     data=new T[s](); 
    } 
    myArrayImpl(const myArrayImpl & other){ 
     data=new T[s]; 
     copy(other.data,other.data+s,data); 
    } 
    myArrayImpl& operator=(const myArrayImpl& other){ 
     T* olddata = data; // !!! need to store old data 
     data=new T[s]; 
     copy(other.data,other.data+s,data); 
     delete [] olddata; //!!! to delete it after copying 
     return *this; 
    } 
    ~myArrayImpl(){delete [] data;} 
}; 

然后作一般性实施 - 注意的value_typesetAll的定义:

template <class T, int s> 
class myArray : private myArrayImpl<T,s> { 
    typedef myArrayImpl<T,s> Impl; 
public: 
    using Impl::operator[]; 
    myArray() : Impl() {} 
    typedef T value_type; // !!! 
    explicit myArray(const value_type& value) { 
     setAll(value); 
    } 
    void setAll(const value_type& value) { 
     fill(this->data, this->data + s, value); 
    } 
}; 

而对于myArray的myarray的的专业版 - 另见value_typesetAll差异:

template <class T, int s1, int s2> 
class myArray<myArray<T,s2>,s1> : private myArrayImpl<myArray<T,s2>,s1> { 
    typedef myArrayImpl<myArray<T,s2>,s1> Impl; 
public: 
    using Impl::operator[]; 
    myArray() : Impl() {} 
    typedef typename myArray<T,s2>::value_type value_type; // !!! 
    explicit myArray(const value_type& value) { 
     setAll(value); 
    } 
    void setAll(const value_type& value) { 
     for_each(this->data, this->data + s1, [value](myArray<T,s2>& v) { v.setAll(value); }); 
    } 
}; 

与用法:

int main() { 
    myArray<myArray<myArray<int,7>,8>,9> a(7); 
    std::cout << a[0][0][0] << std::endl; 
    std::cout << a[8][7][6] << std::endl; 
} 

完整的示例在这里:http://ideone.com/0wdT9D

+0

为什么不模板明确myArray的(U const的&U)?也就是说,接受任何类型,并且如果它不能被用于构造内容,就会得到一个错误。实际上,我们想要说的是“任何可以被用于构建我的内容对我来说是公平的游戏” - 你的工作方式,如果你的内容是myArrays。 – Yakk

+0

@Yakk你也许是对的 - 我没有检查 - 但它似乎是合理的......我只是怕会太笼统。此外 - 任何类型的castable到value_type都可以用在我的解决方案中,并且这个投射只会进行一次 - 而不是[multi]数组中的每个单元格。 – PiotrNycz

+0

这是您的解决方案的一个很好的功能! +1 – Yakk