Essentially, the situation is as follows:
基本上情况如下:
I have a class template (using one template parameter length
of type int
) and want to introduce a static array. This array should be of length length
and contain the elements 1
to length
.
我有一个类模板(使用一个类型为int的模板参数长度),并希望引入一个静态数组。这个数组的长度应该为长度,并且包含元素1到长度。
The code looks as follows up to now:
代码如下所示:
template<int length>
class myClass{
static int array[length];
};
Then I wanted to write a line for initalizing the array
然后我想为数组的输入写一行。
// of course, the line below does not work as intended.
template<int length> int myClass<length>::array[length]={1,2, ..., length};
(How) can this be achieved?
(如何)实现这一点?
9 个解决方案
#1
2
Use "static constructor" idiom.
使用“静态构造函数”的成语。
// EDIT 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];
}
}
#2
5
You can't do that with C-style arrays because they don't have value semantics.
你不能用c样式的数组来做,因为它们没有值语义。
If you use something like std::tr1::array
however then you could easily do what you want by initialising to a function result, or by using an iterator that generates those values.
如果您使用的是std::tr1::数组,那么您可以通过初始化到函数的结果,或者使用生成这些值的迭代器来轻松地完成您想要的操作。
#3
1
You can write a wrapper class, but I'm sure there are cleaner solutions:
您可以编写一个包装类,但我确信有更干净的解决方案:
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
It seems tough. The closest approach that i can think of would be the following :
看起来艰难。我能想到的最接近的方法是:
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
I think this only works in C++0x. In C++03 whatever you do - you will end up with a dynamically initialized array, and thus potentially have initialization order problems. The following C++0x code won't have such problems.
我认为这只适用于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;
};
#6
0
embed a for loop in a static constructor that runs up to length, its basically the same as using the initializer:
在一个静态构造函数中嵌入一个for循环,这个循环的长度可以达到一定的长度,基本上和使用初始化器是一样的:
for(int i = 0; i < length; i++)
array[i] = i + 1;
#7
0
Here is an example using Boost.MPL:
这里有一个使用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;
}
}
Note that the array is larger than length
; currently its size is fixed.
注意数组大于长度;目前它的大小是固定的。
#8
0
You can use explicit template instantiation of an additional static member whose constructor takes care of filling out the entries:
您可以使用附加静态成员的显式模板实例化,该成员的构造函数负责填写条目:
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;
}
Or, since a similar (probably better) solution has been already shown above by Benoit, here's a template recursive version, just for fun:
或者,由于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;
}
Now, different compilers support different levels of template recursion (and this technique is compiler expensive) so, careful..."Here Be Dragons" ;-)
现在,不同的编译器支持不同级别的模板递归(这种技术的编译成本很高),所以,小心……“这里是龙”;-)
Oh, one more thing, you don't need to redefine the array in the specialized version of myClass, so you can get rid of instantiating array[1]:
哦,还有一件事,你不需要在myClass的专门版本中重新定义数组,所以你可以摆脱实例化数组[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;
}
};
#9
0
Can't you wrap the array in a static function, so for example,
你不能把数组封装在一个静态函数中,
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;
};
};
and then access it like,
然后像这样访问它,
myClass<4>::myArray()[2] = 42;
It will be initialised on first use, and on following accesses since initd
is static, if(!initd)
will be false and the initialisation step will be skipped.
由于initd是静态的,如果(!initd)是假的,并且初始化步骤将被跳过,那么它将在首次使用时被初始化,并在后续访问中被初始化。
#1
2
Use "static constructor" idiom.
使用“静态构造函数”的成语。
// EDIT 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];
}
}
#2
5
You can't do that with C-style arrays because they don't have value semantics.
你不能用c样式的数组来做,因为它们没有值语义。
If you use something like std::tr1::array
however then you could easily do what you want by initialising to a function result, or by using an iterator that generates those values.
如果您使用的是std::tr1::数组,那么您可以通过初始化到函数的结果,或者使用生成这些值的迭代器来轻松地完成您想要的操作。
#3
1
You can write a wrapper class, but I'm sure there are cleaner solutions:
您可以编写一个包装类,但我确信有更干净的解决方案:
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
It seems tough. The closest approach that i can think of would be the following :
看起来艰难。我能想到的最接近的方法是:
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
I think this only works in C++0x. In C++03 whatever you do - you will end up with a dynamically initialized array, and thus potentially have initialization order problems. The following C++0x code won't have such problems.
我认为这只适用于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;
};
#6
0
embed a for loop in a static constructor that runs up to length, its basically the same as using the initializer:
在一个静态构造函数中嵌入一个for循环,这个循环的长度可以达到一定的长度,基本上和使用初始化器是一样的:
for(int i = 0; i < length; i++)
array[i] = i + 1;
#7
0
Here is an example using Boost.MPL:
这里有一个使用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;
}
}
Note that the array is larger than length
; currently its size is fixed.
注意数组大于长度;目前它的大小是固定的。
#8
0
You can use explicit template instantiation of an additional static member whose constructor takes care of filling out the entries:
您可以使用附加静态成员的显式模板实例化,该成员的构造函数负责填写条目:
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;
}
Or, since a similar (probably better) solution has been already shown above by Benoit, here's a template recursive version, just for fun:
或者,由于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;
}
Now, different compilers support different levels of template recursion (and this technique is compiler expensive) so, careful..."Here Be Dragons" ;-)
现在,不同的编译器支持不同级别的模板递归(这种技术的编译成本很高),所以,小心……“这里是龙”;-)
Oh, one more thing, you don't need to redefine the array in the specialized version of myClass, so you can get rid of instantiating array[1]:
哦,还有一件事,你不需要在myClass的专门版本中重新定义数组,所以你可以摆脱实例化数组[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;
}
};
#9
0
Can't you wrap the array in a static function, so for example,
你不能把数组封装在一个静态函数中,
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;
};
};
and then access it like,
然后像这样访问它,
myClass<4>::myArray()[2] = 42;
It will be initialised on first use, and on following accesses since initd
is static, if(!initd)
will be false and the initialisation step will be skipped.
由于initd是静态的,如果(!initd)是假的,并且初始化步骤将被跳过,那么它将在首次使用时被初始化,并在后续访问中被初始化。