代码之家  ›  专栏  ›  技术社区  ›  phimuemue

C++:根据模板参数填充数组

  •  12
  • phimuemue  · 技术社区  · 14 年前

    我有一个类模板(使用一个模板参数 length 类型 int )我们想引入一个静态数组。此数组的长度应为 长度 1 长度 .

    目前代码如下:

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

    (如何)实现这一点?

    9 回复  |  直到 14 年前
        1
  •  2
  •   adf88    14 年前

    使用“静态构造函数”习惯用法。

    #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];
        }
    }
    
        2
  •  5
  •   Peter Alexander    14 年前

    如果你用 std::tr1::array 但是,通过初始化函数结果,或者通过使用生成这些值的迭代器,您可以轻松地执行所需的操作。

        3
  •  1
  •   fredoverflow    14 年前

    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;
    };
    
        4
  •  1
  •   Benoît photo_tom    14 年前

    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;
    
        5
  •  1
  •   tjm    14 年前

    你不能用静态函数包装数组,比如,

    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)

        6
  •  1
  •   Johannes Schaub - litb    14 年前

    我认为这只能在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;
    };
    
        7
  •  0
  •   Community Mike Causer    7 年前

    将for循环嵌入到 static constructor

    for(int i = 0; i < length; i++)
        array[i] = i + 1;
    
        8
  •  0
  •   Philipp    14 年前

    下面是一个使用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

        9
  •  0
  •   blue scorpion    14 年前

    您可以使用附加静态成员的显式模板实例化,该静态成员的构造函数负责填写条目:

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

    现在,不同的编译器支持不同级别的模板递归(而且这种技术是编译器昂贵的),所以,小心……“这里是龙”;—)

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