12

基本的に、状況は次のとおりです。

クラス テンプレート ( lengthtype の 1 つのテンプレート パラメーターを使用int) があり、静的配列を導入したいと考えています。この配列は、長さがあり、~lengthの要素1を含む必要がありますlength

現在までのコードは次のようになります。

template<int length>
class myClass{
    static int array[length];
};

次に、配列を初期化するための行を書きたかった

// of course, the line below does not work as intended.
template<int length> int myClass<length>::array[length]={1,2, ..., length};

(どのように)これを達成できますか?

4

9 に答える 9

5

C スタイルの配列には値のセマンティクスがないため、これを行うことはできません。

ただし、次のようなものを使用するstd::tr1::arrayと、関数の結果に初期化するか、それらの値を生成する反復子を使用することで、必要なことを簡単に実行できます。

于 2010-07-01T12:05:12.647 に答える
2

「静的コンストラクター」イディオムを使用します。

// 編集 2

#include <iostream>

template<int length>
class myClass {
public:
    typedef int ArrayType[length];

    static struct StaticData {
        ArrayType array;

        StaticData()
        {
            for (int i = 0; i < length; i++) array[i] = i;
        }
    }
    static_data;

    static ArrayType &array;
};

template<int length>
typename myClass<length>::StaticData myClass<length>::static_data;

template<int length>
typename myClass<length>::ArrayType &myClass<length>::array = myClass<length>::static_data.array;

int main(int argc, char** argv) {
    const int LEN = 5;
    for (int i = 0; i < LEN; i++) {
        std::cout << myClass<LEN>::array[i];
    }
}
于 2010-07-01T12:04:13.727 に答える
1

配列を静的関数でラップできないので、たとえば、

template<int length>
class myClass {
    static int* myArray() {
        static bool initd = false;
        static int array[length];
        if(!initd) {
            for(int i=0; i<length; ++i) {
                array[i] = i+1;
            }
            initd = true;
        }
        return array;
    };
};

そして、次のようにアクセスします。

myClass<4>::myArray()[2] = 42;

最初の使用時に初期化され、次のアクセスでinitdは静的でif(!initd)あるため false になり、初期化手順はスキップされます。

于 2010-07-01T18:42:40.667 に答える
1

これは C++0x でのみ機能すると思います。C++03 では、何をしても、動的に初期化された配列になるため、初期化順序の問題が発生する可能性があります。次の C++0x コードには、このような問題はありません。

template<int...>
struct myArray;

template<int N, int ...Ns>
struct myArray<N, Ns...> : myArray<N-1, N, Ns...> { };

template<int ...Ns>
struct myArray<0, Ns...> {
    static int array[sizeof...(Ns)];
};

template<int ...Ns>
int myArray<0, Ns...>::array[sizeof...(Ns)] = { Ns... } ;

template<int length>
class myClass : myArray<length> {
    using myArray<length>::array;
};
于 2010-07-02T00:07:33.567 に答える
1

ラッパー クラスを作成できますが、よりクリーンなソリューションがあると確信しています。

template <size_t length>
class array_init_1_to_n
{
    int array[length];

public:

    array_init_1_to_n()
    {
        for (int i = 0; i < length; ++i)
        {
            array[i] = i + 1;
        }
    }

    operator int*()
    {
        return array;
    }

    operator const int*() const
    {
        return array;
    }
};

template<size_t length>
class myClass{
    static array_init_1_to_n<length> array;
};
于 2010-07-01T12:08:57.490 に答える
1

大変そうです。私が考えることができる最も近いアプローチは次のとおりです。

template<int length>
class myClass
{
  public:
    myClass()
    {
      static InitializeArray<length> initializeArray(&array);
    }
    template<int length>
    class InitializeArray
    {
    public:
      InitializeArray(int* array) 
      {
        for(int i = 0; i < length ; ++i)
        array[i] = i;
      }
    };
    static int array[length];
    static myClass instance;
};
template<int length> int myClass<length>::array[length];
template<int length> myClass myClass::instance;
于 2010-07-01T12:09:44.033 に答える
0

コンストラクターがエントリの入力を処理する追加の静的メンバーの明示的なテンプレートインスタンス化を使用できます。

template<int length>
class myClass{
public:
    static int array[length];

    typedef enum{LENGTH=length} size_;

    struct filler
    {
        filler(void)
        {
            for(int i=0;i<LENGTH;++i)
                array[i]=i+1;
        }
    };

    static filler fill_;
};

// of course, the line[s] below now do work as intended.
template<int length> 
int myClass<length>::array[length];

//static member definition
template<int length>
typename myClass<length>::filler myClass<length>::fill_;

//explicit template instantiation
template myClass<5>::filler myClass<5>::fill_;

int main(void)
{
    for(int i=0;i<myClass<5>::LENGTH;++i)
        cout<<myClass<5>::array[i]<<endl;

    return 0;
}

または、同様の(おそらくより良い)ソリューションがBenoitによってすでに上に示されているので、ここにテンプレートの再帰バージョンがあります。

//recursive version:
template<int length>
class myClass{
public:
    static int array[length];

    typedef enum{LENGTH=length} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
        myClass<length-1>::do_fill(the_array);
    }

    struct filler
    {
        filler(void)
        {
            /*for(int i=0;i<LENGTH;++i)
                array[i]=i+1;*/
            do_fill(array);
        }
    };

    static filler fill_;
};

//explicit specialization to end the recursion
template<>
class myClass<1>{
public:
    static int array[1];

    typedef enum{LENGTH=1} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
    }
};

//definition of the explicitly specialized version of the array
//to make the linker happy:
int myClass<1>::array[1];

// of course, the line below does not work as intended.
template<int length> 
int myClass<length>::array[length];

//static member definition
template<int length>
typename myClass<length>::filler myClass<length>::fill_;

//explicit template instantiation
template myClass<5>::filler myClass<5>::fill_;

int main(void)
{
    for(int i=0;i<myClass<5>::LENGTH;++i)
        cout<<myClass<5>::array[i]<<endl;

    return 0;
}

現在、さまざまなコンパイラがさまざまなレベルのテンプレート再帰をサポートしているため(この手法はコンパイラにコストがかかります)、注意してください... "Here Be Dragons" ;-)

ああ、もう1つ、myClassの特殊バージョンで配列を再定義する必要がないので、array[1]のインスタンス化を取り除くことができます。

//explicit specialization to end the recursion
template<>
class myClass<1>{
public:
    typedef enum{LENGTH=1} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
    }
};
于 2010-07-01T16:38:43.260 に答える
0

長さまで実行される for ループを静的コンストラクターに埋め込みます。基本的には、初期化子を使用するのと同じです。

for(int i = 0; i < length; i++)
    array[i] = i + 1;
于 2010-07-01T12:09:06.463 に答える
0

Boost.MPL を使用した例を次に示します。

#include <cstddef>
#include <iostream>

#include <boost/mpl/range_c.hpp>
#include <boost/mpl/string.hpp>

template<std::size_t length>
struct myClass {
  static const std::size_t Length = length;
  typedef typename boost::mpl::c_str< boost::mpl::range_c<std::size_t, 1, length + 1> > Array;
};

int main() {
  // check whether the array really contains the indented values
  typedef myClass<10> test;
  for (std::size_t i = 0; i < test::Length; ++i) {
    std::cout << test::Array::value[i] << std::endl;
  }
}

配列が より大きいことに注意してくださいlength。現在、そのサイズは固定されています。

于 2010-07-01T12:29:16.347 に答える