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;

aは30x20x10の配列になり、通常の配列ブラケット(a [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に設定されていません。標準のベクトルクラスがこれをどのように実現するかを知っている人はいますか?どんな助けでも素晴らしいでしょう。ありがとう!

4

3 に答える 3

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);
 }

可変個引数テンプレートに興味がある場合は、可変個引数で埋められた初期化子リストを含む、さらにグロテスクなものを作成するかもしれませんが、1週間で十分な学習ができたと思います。

使用の根本的な欠陥に注意してnewください。どちらのバージョンでも、クラスTを何らかの「デフォルト」状態でインスタンス化でき、2番目のバージョンではデフォルト状態を必要しない場合でも、割り当て可能である必要があります。そのため、「実際の」ライブラリはメモリ割り当てとオブジェクト構築を分離newし、配置バージョンでない限り、式は表示されません。

于 2012-11-05T16:39:40.007 に答える
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_type次に、一般的な実装を行います-との定義に注意してくださいsetAll

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_typeくださいsetAll

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

于 2012-11-05T17:36:58.920 に答える
1

std :: vectorは、メモリブロックに新しい配置を使用します。コードの2行目にメモリを割り当てた後、データを作成します。

このテクニックはあなたにも役立ちます。デストラクタも手動で呼び出す必要があるため、新しい配置には注意してください。

これは、新しい配置のない中途半端なルートです。

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の配列の配列の最も外側の配列を作成したものに渡されます。それが気に入らない場合は、コンパイラエラーが発生します。ほぼ完全に読めないメッセージ。

于 2012-11-05T16:44:15.273 に答える