Compile-time array initialization

Started by
20 comments, last by DigitalDelusion 19 years, 10 months ago
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
Advertisement
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
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

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

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

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
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<T>'
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<T>'
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<unsigned int T>
template<unsigned int N> struct CompilerErrorExample<T>::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<T>::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.
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

This topic is closed to new replies.

Advertisement