Skip to main content
GameDev.net gamedev.net
🔒 Locked

Compile-time array initialization

Started by Opwiz Jul 6, 2004 at 8:27 AM 20 replies 4.3k views
Original Post
Opwiz
Opwiz
Is there a way to initialize an array of size N at compile time (where N is a constant integer specified as a template parameter)? E.g. if I wish the elements to be initialized to N^2/i (where i is the array index).
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
Zahlman
Zahlman
Wrap it in a templated class?
Create a templated function that returns such an array?
Opwiz
Opwiz
I'm not sure how to do it. Can you give an example?

Remember I want the initialized array available at compile-time.
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
rypyr
rypyr
Quote:
Original post by Opwiz
Is there a way to initialize an array of size N at compile time (where N is a constant integer specified as a template parameter)? E.g. if I wish the elements to be initialized to N^2/i (where i is the array index).


So you want the 0th element to hold infinity? ;)
Opwiz
Opwiz
Quote:
have a look at this: http://www.gamedev.net/community/forums/topic.asp?topic_id=252723&whichpage=1

Nice :). Thank you.
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
Opwiz
Opwiz
Quote:
So you want the 0th element to hold infinity? ;)

Ok, that was not a very good example :)
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
Opwiz
Opwiz
This is what I've managed to do:

template<int N>class ClassWithStaticArray{public:	void PrintElems()	{		std::cout << dummy << std::endl;			for(int i = 0; i < N; ++i)		{			std::cout << i << ": " << elem << std::endl;		}	}private:	template<int D>	static int Init()	{		return elem[D] = Init<D - 1>() - 1;	}	template<>	static int Init<0>()	{		return elem[0] = N;	}	static int elem[N];	static const int dummy;};template<int N>int ClassWithStaticArray<N>::elem[N];template<int N>const int ClassWithStaticArray<N>::dummy = Init<N>();


I have to use a static array but that happens to be what I need so that is not really a problem. The static array is initialized at run-time but only if the "dummy" variable is referenced. I want it to be generated at compile-time, or atleast without having to reference a dummy variable. Any ideas?
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
Opwiz
Opwiz
Slightly better:

template<int N>class ClassWithStaticArray{public:	void PrintElems()	{		for(int i = 0; i < N; ++i)		{			std::cout << i << ": " << ar << std::endl;		}	}private:	template<int D>	static int& Init()	{		return elem[D] = Init<D - 1>() - 1;	}	template<>	static int& Init<0>()	{		return elem[0] = N;	}	static int elem[N];	static int* ar;};template<int N>int ClassWithStaticArray<N>::elem[N];template<int N>int* ClassWithStaticArray<N>::ar = &Init<N>() - N;


Whenever I need to reference the array I use the pointer "ar" that gets initialized when first used. Still generated at run-time though. A cleaner run-time solution would be to initialize the array at the constructor and use a flag to ensure that it only gets initialized once.
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
DigitalDelusion
DigitalDelusion
this is both, horrible and beautiful ;) but works for me, to use it simply substitue the fib meta function template.

#include <cstdio>#include <cstdlib>template <template<unsigned> class F, unsigned N>class value_array{	template <template<unsigned> class F, unsigned N>	class value_holder	{		value_holder<F,N-1> base;		const unsigned val;	public:		value_holder(void): val( F<N>::val){}	};	template <template<unsigned> class F>	class value_holder<F,0>	{		const unsigned val;	public:		value_holder(void): val( F<0>::val){}	};	static const value_holder<F,N> values;public:	static const unsigned size = N;	unsigned operator[](unsigned n){ return *(reinterpret_cast<const unsigned*>( &values)+n);}};template <template<unsigned> class F, unsigned N>const typename value_array<F,N>::value_holder<F,N> value_array<F,N>::values;//need a test "function"template <unsigned N>struct fib{	enum {val = fib<N-1>::val + fib<N-2>::val};};template <>struct fib<0>{ enum {val = 1};};template <>struct fib<1>{ enum {val = 1};};int main(void){	static value_array<fib, 10> fibo;	for(unsigned n = 0; n != 10; ++n)		printf("%d ", fibo[n]);	puts("");	system("pause");}


looking at the asm output for it you can find this gem
_DATA	SEGMENT?values@?$value_array@Ufib@@$09@@0V?$value_holder@Ufib@@$09@1@B DD 01H ; value_array<fib,10>::values	DD	01H	DD	02H	DD	03H	DD	05H	DD	08H	DD	0dH	DD	015H	DD	022H	DD	037H	DD	059H_DATA	ENDS


that's compile values =)

and yes, Im insane...
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Fruny
Fruny
Have you thought about code generation? It is probably the simplest solution...

// gen_array_cpp.cpp#include <iostream>#include <fstream>int main(int argc, char* argv[]){   if(argc<2)   {      std::cerr << "Usage: " << argv[0] << " <array size>" << std::endl;      return 1;   }   size_t array_size = atoi(argv[1]);   std::ofstream array_h("array.h");   if(!array_h)   array_h << "// AUTOMATICALLY GENERATED FILE, DO NOT MODIFY.\n"           << "#ifndef INCLUDE_ARRAY_H\n"           << "#define INCLUDE_ARRAY_H\n"           << std::endl;;   array_h << "extern int array[" << array_size << "];" << std::endl;   array_h << "#endif // INCLUDE_ARRAY_H" << std::endl;   array_h.close();   std::ofstream array_cpp("array.cpp");   if(!array_cpp)   {      std::cerr << "Could not open file array.cpp" << std::endl;      return 1;   }   array_cpp << "// AUTOMATICALLY GENERATED FILE, DO NOT MODIFY.\n"   array_cpp << "int array[" << array_size << "] = {" << std::endl;   for(size_t i=0; i<array_size; ++i)         array_cpp << "  " << array_size*array_size / (i+1) << "," << std::endl;   array_cpp << "};" << std::endl;   array_cpp.close();}


or in python

import systry:   array_size = int(sys.argv[1])except:   print >> sys.stderr, "Usage: %s <array size>" % sys.argv[0]   exit(1)array_h = file("array.h","w")print >> array_h, "// AUTOMATICALLY GENERATED FILE, DO NOT MODIFY."print >> array_h, "#ifndef INCLUDE_ARRAY_H"print >> array_h, "#define INCLUDE_ARRAY_H"print >> array_hprint >> array_h, "extern int array[%d];" % array_sizeprint >> array_hprint >> array_h, "#endif // INCLUDE_ARRAY_H"array_h.close()array_cpp = file("array.cpp", "w")print >> array_cpp, "// AUTOMATICALLY GENERATED FILE, DO NOT MODIFY."print >> array_cppprint >> array_cpp, "array[%d] = {" % array_sizefor i in xrange(array_size):   print >> array_cpp, "  %d," % (array_size**2 / (i+1))print >> array_cpp, "};"array_cpp.close()


You add those programs to your build process, and use the files they generate as source files in your project. Simple, maintainable, and not relying on any complex language tricks that may or may not be supported by your compiler.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Opwiz
Opwiz
Quote:
this is both, horrible and beautiful ;) but works for me, to use it simply substitue the fib meta function template.

I'm amazed it compiles :) very nice. Your example worked fine. Got internal compiler error though when I tried to implement it inside my class (my table value algorithm needs to use a template parameter specified for the class so I can't put the algorithm outside the class).
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
DigitalDelusion
DigitalDelusion
Sounds odd, would you mind posting code for that Im curious.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Opwiz
Opwiz
Quote:
Have you thought about code generation? It is probably the simplest solution...

It has crossed my mind.. But my first thought was that it would be complicated and hard to maintain. You would have to change the input parameters to the code generator each time you change the size of the static array. Also if you plan to use several instances of the static array (initialized differently depending on some template parameters) it becomes impossible to implement with code generation.
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
Fruny
Fruny
Quote:
Original post by Opwiz
It has crossed my mind.. But my first thought was that it would be complicated and hard to maintain.


It's not that bad, really. :)


Quote:
You would have to change the input parameters to the code generator each time you change the size of the static array.


It can be done via a command-line parameter to the code generator. If it's part of your build process, it'll be transparent.

Quote:
Also if you plan to use several instances of the static array (initialized differently depending on some template parameters) it becomes impossible to implement with code generation.


Ok, it does get a bit more complicated, though still feasible ;)
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Opwiz
Opwiz
Quote:
Sounds odd, would you mind posting code for that Im curious.

This generates
fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 2701)

I'm using MSVC++ .NET 7.1

template<unsigned T>class CompilerErrorExample{public:	CompilerErrorExample()	{		for(unsigned i = 0; i < T; ++i)		{			std::cout << i << ": " << fibo << std::endl;		}	}	~CompilerErrorExample()	{	}	template<unsigned N>	struct fib	{		enum {val = fib<N-1>::val + fib<N-2>::val};	};	template <>	struct fib<0>{ enum {val = 1};};	template <>	struct fib<1>{ enum {val = 1};};	static value_array<fib, T> fibo;};template<unsigned T>value_array<CompilerErrorExample<T>::fib, T> CompilerErrorExample<T>::fibo;int main(void){	CompilerErrorExample<10> e;	return 0;}


I'm not sure if the declaration of fibo is correct but the compiler generates internal error with or without.

[Edit: corrected code]
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity
DigitalDelusion
DigitalDelusion
I just noticed that, just putting the generative templte inside the class somehow confuses the compiler, thinking 'bout a general workaroudn for your scenario.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
C-Junkie
C-Junkie
Since msvc crapped out on you, here are the errors gcc gives me:

$ g++ er.cc -o er
er.cc:26: error: explicit specialization in non-namespace scope class
CompilerErrorExample'
er.cc:26: error: enclosing class templates are not explicitly specialized
er.cc:27: error: template parameters not used in partial specialization:
er.cc:27: error:
T'
er.cc:29: error: explicit specialization in non-namespace scope class
CompilerErrorExample'
er.cc:29: error: enclosing class templates are not explicitly specialized
er.cc:30: error: template parameters not used in partial specialization:
er.cc:30: error:
T'
er.cc:32: error: ISO C++ forbids declaration of value_array' with no type
er.cc:32: error: template-id
value_array
template struct CompilerErrorExample::fib, T>' used as a
declarator
er.cc:32: error: parse error before ;' token
er.cc:37: error: syntax error before
<' token
er.cc:37: error: T' was not declared in this scope
er.cc:37: error: template argument 1 is invalid
er.cc:37: error: ISO C++ forbids declaration of
fibo' with no type
er.cc: In constructor CompilerErrorExample::CompilerErrorExample() [with
unsigned int T = 10]':
er.cc:41: instantiated from here
er.cc:12: error: invalid types
int[unsigned int]' for array subscript

This might help find out what's wrong.
Fruny
Fruny
gcc says:
foo.cc:25: error: explicit specialization in non-namespace scope `class   CompilerErrorExample<T>'foo.cc:25: error: enclosing class templates are not explicitly specializedfoo.cc:26: error: template parameters not used in partial specialization:foo.cc:26: error:         `T'


idem on 28/29.

It doesn't like your nested specializations. Take fib out of CompilerErrorExample.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Opwiz
Opwiz
Quote:
Since msvc crapped out on you, here are the errors gcc gives me:

Did you include DigitalDelusions value_array code?
www.marklightforunity.com | MarkLight: Markup Extension Framework for Unity

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.