[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Templated array of templates specialized by array index

npankey

10/11/2008 9:58:00 PM

I've started experimenting with template metaprogramming in a small
project of mine. What I'm trying to accomplish is to generate a static
array of templated objects that get specialized based on there
position in the array. This should be possible but I can't figure out
exactly how to accomplish this.

The below code should better illustrate what I'm trying to do:

template <int I>
class Item
{
int X() { /*do default */ }
}

template <>
class Item<0>
{
int X() { /* do something special */ }
};

template <int N>
class Array
{
// The following obviously won't work
// How do I push this type of initialization to compile time???
Array()
{
for(int i=0; i<N; i++)
{
data[i] = Item<i>();
}
}

Item data[N];
}

int main()
{
Array<5> items;
/* do stuff with items */
return 0;
}
6 Answers

Ian Collins

10/11/2008 10:06:00 PM

0

npankey@gmail.com wrote:
> I've started experimenting with template metaprogramming in a small
> project of mine. What I'm trying to accomplish is to generate a static
> array of templated objects that get specialized based on there
> position in the array. This should be possible but I can't figure out
> exactly how to accomplish this.
>
Not easily. Don't forget each specialisation of an Item is a unique
class, so you can have a array of different Items.

It you make Item polymorphic with a concrete base class and use an array
of base class pointers you might be able to make progress.

--
Ian Collins

Kai-Uwe Bux

10/11/2008 10:21:00 PM

0

npankey@gmail.com wrote:

> template <int I>
> class Item
> {
> int X() { /*do default */ }
> }
>
> template <>
> class Item<0>
> {
> int X() { /* do something special */ }
> };
>
> template <int N>
> class Array
> {
> // The following obviously won't work
> // How do I push this type of initialization to compile time???
> Array()
> {
> for(int i=0; i<N; i++)
> {
> data[i] = Item<i>();
> }
> }
>
> Item data[N];
> }
>
> int main()
> {
> Array<5> items;
> /* do stuff with items */
> return 0;
> }

Based on your code:

template <int I>
struct Item {

static
void put ( int* where ) {
Item<I-1>::put( where );
where[I] = Item<I>::X();
}

static
int X() {
return ( Item<I-1>::X() + Item<I-2>::X() );
}

};

template <>
struct Item<0> {

static
void put ( int* where ) {
where[0] = Item<0>::X();
}

static
int X() {
return ( 1 );
}

};

template <>
struct Item<1> {

static
void put ( int* where ) {
where[0] = Item<0>::X();
where[1] = Item<1>::X();
}

static
int X() {
return ( 1 );
}

};

template < int N >
struct Array {

Array() {
Item<N-1>::put( data );
}

int data[N];

};

#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main()
{
Array<5> items;
std::copy( items.data, items.data+5,
std::ostream_iterator<int>( std::cout, "\n" ) );
/* do stuff with items */
return 0;
}


Note, however, that the computation is not really done at compile time since
the static functions are executed at runtime. The following fixes at least
that:

template <int I>
struct Item {

static
void put ( int* where ) {
Item<I-1>::put( where );
where[I] = Item<I>::value;
}

static int const value =
Item<I-1>::value + Item<I-2>::value;

};

template <>
struct Item<0> {

static
void put ( int* where ) {
where[0] = Item<0>::value;
}

static int const value = 1;

};

template <>
struct Item<1> {

static
void put ( int* where ) {
where[0] = Item<0>::value;
where[1] = Item<1>::value;
}

static int const value = 1;

};

template < int N >
struct Array {

Array() {
Item<N-1>::put( data );
}

int data[N];

};

#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main()
{
Array<5> items;
std::copy( items.data, items.data+5,
std::ostream_iterator<int>( std::cout, "\n" ) );
/* do stuff with items */
return 0;
}


The array itself is populated at runtime in the constructor of Array. I
don't see a way to push that into compile time.


Best

Kai-Uwe Bux

npankey

10/11/2008 11:37:00 PM

0

On Oct 11, 3:20 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> npan...@gmail.com wrote:
> > template <int I>
> > class Item
> > {
> > int X() { /*do default */ }
> > }
>
> > template <>
> > class Item<0>
> > {
> > int X() { /* do something special */ }
> > };
>
> > template <int N>
> > class Array
> > {
> > // The following obviously won't work
> > // How do I push this type of initialization to compile time???
> > Array()
> > {
> > for(int i=0; i<N; i++)
> > {
> > data[i] = Item<i>();
> > }
> > }
>
> > Item data[N];
> > }
>
> > int main()
> > {
> > Array<5> items;
> > /* do stuff with items */
> > return 0;
> > }
>
> Based on your code:
>
> template <int I>
> struct Item {
>
>   static
>   void put ( int* where ) {
>     Item<I-1>::put( where );
>     where[I] = Item<I>::X();
>   }
>
>   static
>   int X() {
>     return ( Item<I-1>::X() + Item<I-2>::X() );
>   }
>
> };
>
> template <>
> struct Item<0> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::X();
>   }
>
>   static
>   int X() {
>     return ( 1 );
>   }
>
> };
>
> template <>
> struct Item<1> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::X();
>     where[1] = Item<1>::X();
>   }
>
>   static
>   int X() {
>     return ( 1 );
>   }
>
> };
>
> template < int N >
> struct Array {
>
>   Array() {
>     Item<N-1>::put( data );
>   }
>
>   int data[N];
>
> };
>
> #include <iostream>
> #include <ostream>
> #include <iterator>
> #include <algorithm>
>
> int main()
> {
>     Array<5> items;
>     std::copy( items.data, items.data+5,
>                std::ostream_iterator<int>( std::cout, "\n" ) );
>     /* do stuff with items */
>     return 0;
>
> }
>
> Note, however, that the computation is not really done at compile time since
> the static functions are executed at runtime. The following fixes at least
> that:
>
> template <int I>
> struct Item {
>
>   static
>   void put ( int* where ) {
>     Item<I-1>::put( where );
>     where[I] = Item<I>::value;
>   }
>
>   static int const value =
>     Item<I-1>::value + Item<I-2>::value;
>
> };
>
> template <>
> struct Item<0> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::value;
>   }
>
>   static int const value = 1;
>
> };
>
> template <>
> struct Item<1> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::value;
>     where[1] = Item<1>::value;
>   }
>
>   static int const value = 1;
>
> };
>
> template < int N >
> struct Array {
>
>   Array() {
>     Item<N-1>::put( data );
>   }
>
>   int data[N];
>
> };
>
> #include <iostream>
> #include <ostream>
> #include <iterator>
> #include <algorithm>
>
> int main()
> {
>     Array<5> items;
>     std::copy( items.data, items.data+5,
>                std::ostream_iterator<int>( std::cout, "\n" ) );
>     /* do stuff with items */
>     return 0;
>
> }
>
> The array itself is populated at runtime in the constructor of Array. I
> don't see a way to push that into compile time.
>
> Best
>
> Kai-Uwe Bux

Alright, so I'm getting a little closer and now I've at least got code
that compiles

struct Bar
{
int X() { return -1; }
};

template <int I>
struct Foo : Bar {};

template <>
struct Foo<0>
{
int X() { return 0; }
}

template <int N>
class Array
{
Bar data[N];
}

int main()
{
// Now I need to figure out how doing this ...
Array<3> array1;

// ... can essentially result in this
Bar array2[3] = {Foo<0>(), Foo<1>(), Foo<2>()};
}

npankey

10/11/2008 11:41:00 PM

0

On Oct 11, 3:20 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> npan...@gmail.com wrote:
> > template <int I>
> > class Item
> > {
> > int X() { /*do default */ }
> > }
>
> > template <>
> > class Item<0>
> > {
> > int X() { /* do something special */ }
> > };
>
> > template <int N>
> > class Array
> > {
> > // The following obviously won't work
> > // How do I push this type of initialization to compile time???
> > Array()
> > {
> > for(int i=0; i<N; i++)
> > {
> > data[i] = Item<i>();
> > }
> > }
>
> > Item data[N];
> > }
>
> > int main()
> > {
> > Array<5> items;
> > /* do stuff with items */
> > return 0;
> > }
>
> Based on your code:
>
> template <int I>
> struct Item {
>
>   static
>   void put ( int* where ) {
>     Item<I-1>::put( where );
>     where[I] = Item<I>::X();
>   }
>
>   static
>   int X() {
>     return ( Item<I-1>::X() + Item<I-2>::X() );
>   }
>
> };
>
> template <>
> struct Item<0> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::X();
>   }
>
>   static
>   int X() {
>     return ( 1 );
>   }
>
> };
>
> template <>
> struct Item<1> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::X();
>     where[1] = Item<1>::X();
>   }
>
>   static
>   int X() {
>     return ( 1 );
>   }
>
> };
>
> template < int N >
> struct Array {
>
>   Array() {
>     Item<N-1>::put( data );
>   }
>
>   int data[N];
>
> };
>
> #include <iostream>
> #include <ostream>
> #include <iterator>
> #include <algorithm>
>
> int main()
> {
>     Array<5> items;
>     std::copy( items.data, items.data+5,
>                std::ostream_iterator<int>( std::cout, "\n" ) );
>     /* do stuff with items */
>     return 0;
>
> }
>
> Note, however, that the computation is not really done at compile time since
> the static functions are executed at runtime. The following fixes at least
> that:
>
> template <int I>
> struct Item {
>
>   static
>   void put ( int* where ) {
>     Item<I-1>::put( where );
>     where[I] = Item<I>::value;
>   }
>
>   static int const value =
>     Item<I-1>::value + Item<I-2>::value;
>
> };
>
> template <>
> struct Item<0> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::value;
>   }
>
>   static int const value = 1;
>
> };
>
> template <>
> struct Item<1> {
>
>   static
>   void put ( int* where ) {
>     where[0] = Item<0>::value;
>     where[1] = Item<1>::value;
>   }
>
>   static int const value = 1;
>
> };
>
> template < int N >
> struct Array {
>
>   Array() {
>     Item<N-1>::put( data );
>   }
>
>   int data[N];
>
> };
>
> #include <iostream>
> #include <ostream>
> #include <iterator>
> #include <algorithm>
>
> int main()
> {
>     Array<5> items;
>     std::copy( items.data, items.data+5,
>                std::ostream_iterator<int>( std::cout, "\n" ) );
>     /* do stuff with items */
>     return 0;
>
> }
>
> The array itself is populated at runtime in the constructor of Array. I
> don't see a way to push that into compile time.
>
> Best
>
> Kai-Uwe Bux

Alright, so I'm getting a little closer and now I've at least got code
that compiles

struct Bar
{
int X() { return -1; }
};

template <int I>
struct Foo : Bar {};

template <>
struct Foo<0>
{
int X() { return 0; }
}

template <int N>
class Array
{
Bar data[N];
}

int main()
{
// Now I need to figure out how doing this ...
Array<3> array1;

// ... can essentially result in this
Bar array2[3] = {Foo<0>(), Foo<1>(), Foo<2>()};
}

npankey

10/12/2008 3:03:00 AM

0

On Oct 11, 4:41 pm, npan...@gmail.com wrote:
> On Oct 11, 3:20 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
>
>
> > npan...@gmail.com wrote:
> > > template <int I>
> > > class Item
> > > {
> > > int X() { /*do default */ }
> > > }
>
> > > template <>
> > > class Item<0>
> > > {
> > > int X() { /* do something special */ }
> > > };
>
> > > template <int N>
> > > class Array
> > > {
> > > // The following obviously won't work
> > > // How do I push this type of initialization to compile time???
> > > Array()
> > > {
> > > for(int i=0; i<N; i++)
> > > {
> > > data[i] = Item<i>();
> > > }
> > > }
>
> > > Item data[N];
> > > }
>
> > > int main()
> > > {
> > > Array<5> items;
> > > /* do stuff with items */
> > > return 0;
> > > }
>
> > Based on your code:
>
> > template <int I>
> > struct Item {
>
> >   static
> >   void put ( int* where ) {
> >     Item<I-1>::put( where );
> >     where[I] = Item<I>::X();
> >   }
>
> >   static
> >   int X() {
> >     return ( Item<I-1>::X() + Item<I-2>::X() );
> >   }
>
> > };
>
> > template <>
> > struct Item<0> {
>
> >   static
> >   void put ( int* where ) {
> >     where[0] = Item<0>::X();
> >   }
>
> >   static
> >   int X() {
> >     return ( 1 );
> >   }
>
> > };
>
> > template <>
> > struct Item<1> {
>
> >   static
> >   void put ( int* where ) {
> >     where[0] = Item<0>::X();
> >     where[1] = Item<1>::X();
> >   }
>
> >   static
> >   int X() {
> >     return ( 1 );
> >   }
>
> > };
>
> > template < int N >
> > struct Array {
>
> >   Array() {
> >     Item<N-1>::put( data );
> >   }
>
> >   int data[N];
>
> > };
>
> > #include <iostream>
> > #include <ostream>
> > #include <iterator>
> > #include <algorithm>
>
> > int main()
> > {
> >     Array<5> items;
> >     std::copy( items.data, items.data+5,
> >                std::ostream_iterator<int>( std::cout, "\n" ) );
> >     /* do stuff with items */
> >     return 0;
>
> > }
>
> > Note, however, that the computation is not really done at compile time since
> > the static functions are executed at runtime. The following fixes at least
> > that:
>
> > template <int I>
> > struct Item {
>
> >   static
> >   void put ( int* where ) {
> >     Item<I-1>::put( where );
> >     where[I] = Item<I>::value;
> >   }
>
> >   static int const value =
> >     Item<I-1>::value + Item<I-2>::value;
>
> > };
>
> > template <>
> > struct Item<0> {
>
> >   static
> >   void put ( int* where ) {
> >     where[0] = Item<0>::value;
> >   }
>
> >   static int const value = 1;
>
> > };
>
> > template <>
> > struct Item<1> {
>
> >   static
> >   void put ( int* where ) {
> >     where[0] = Item<0>::value;
> >     where[1] = Item<1>::value;
> >   }
>
> >   static int const value = 1;
>
> > };
>
> > template < int N >
> > struct Array {
>
> >   Array() {
> >     Item<N-1>::put( data );
> >   }
>
> >   int data[N];
>
> > };
>
> > #include <iostream>
> > #include <ostream>
> > #include <iterator>
> > #include <algorithm>
>
> > int main()
> > {
> >     Array<5> items;
> >     std::copy( items.data, items.data+5,
> >                std::ostream_iterator<int>( std::cout, "\n" ) );
> >     /* do stuff with items */
> >     return 0;
>
> > }
>
> > The array itself is populated at runtime in the constructor of Array. I
> > don't see a way to push that into compile time.
>
> > Best
>
> > Kai-Uwe Bux
>
> Alright, so I'm getting a little closer and now I've at least got code
> that compiles
>
> struct Bar
> {
>     int X() { return -1; }
>
> };
>
> template <int I>
> struct Foo : Bar {};
>
> template <>
> struct Foo<0>
> {
>     int X() { return 0; }
>
> }
>
> template <int N>
> class Array
> {
>     Bar data[N];
>
> }
>
> int main()
> {
>     // Now I need to figure out how doing this ...
>     Array<3> array1;
>
>     // ... can essentially result in this
>     Bar array2[3] = {Foo<0>(), Foo<1>(), Foo<2>()};
>
> }
>
>

So after more experimentation and testing I've got this working and
the solution is pretty straight forward


struct Bar
{
virtual int X() { return -1; }
};

template <int I>
struct Foo : Bar
{
virtual int X() { return I; }
};

template <>
struct Foo<0> : Bar
{
virtual int X() { return 50; }
};

template <int N>
class Array
{
public:
Array() { Init(m_data); }

Bar* operator[] (int i) { return m_data[i]; }

protected:
friend class Array<N+1>;

// Recursively initialize our array
static void Init(Bar** data)
{
data[N] = new Foo<N>();
Array<N-1>::Init(data);
}

Bar* m_data[N+1];
};

template <>
class Array<0>
{
protected:
friend class Array<1>;

// Stop the recursion
static void Init(Bar** data)
{
data[0] = new Foo<0>();
}
};

int main()
{
Array<3> array;
for (int i=0; i <= 3; i++)
{
printf("value: %d\n", array[i]->X());
}
}

value: 50
value: 1
value: 2
value: 3

Alex

10/12/2008 3:21:00 PM

0

On 10?12?, ??11?03?, npan...@gmail.com wrote:
> On Oct 11, 4:41 pm, npan...@gmail.com wrote:
>
>
>
>
>
> > On Oct 11, 3:20 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>
> > > npan...@gmail.com wrote:
> > > > template <int I>
> > > > class Item
> > > > {
> > > > int X() { /*do default */ }
> > > > }
>
> > > > template <>
> > > > class Item<0>
> > > > {
> > > > int X() { /* do something special */ }
> > > > };
>
> > > > template <int N>
> > > > class Array
> > > > {
> > > > // The following obviously won't work
> > > > // How do I push this type of initialization to compile time???
> > > > Array()
> > > > {
> > > > for(int i=0; i<N; i++)
> > > > {
> > > > data[i] = Item<i>();
> > > > }
> > > > }
>
> > > > Item data[N];
> > > > }
>
> > > > int main()
> > > > {
> > > > Array<5> items;
> > > > /* do stuff with items */
> > > > return 0;
> > > > }
>
> > > Based on your code:
>
> > > template <int I>
> > > struct Item {
>
> > > static
> > > void put ( int* where ) {
> > > Item<I-1>::put( where );
> > > where[I] = Item<I>::X();
> > > }
>
> > > static
> > > int X() {
> > > return ( Item<I-1>::X() + Item<I-2>::X() );
> > > }
>
> > > };
>
> > > template <>
> > > struct Item<0> {
>
> > > static
> > > void put ( int* where ) {
> > > where[0] = Item<0>::X();
> > > }
>
> > > static
> > > int X() {
> > > return ( 1 );
> > > }
>
> > > };
>
> > > template <>
> > > struct Item<1> {
>
> > > static
> > > void put ( int* where ) {
> > > where[0] = Item<0>::X();
> > > where[1] = Item<1>::X();
> > > }
>
> > > static
> > > int X() {
> > > return ( 1 );
> > > }
>
> > > };
>
> > > template < int N >
> > > struct Array {
>
> > > Array() {
> > > Item<N-1>::put( data );
> > > }
>
> > > int data[N];
>
> > > };
>
> > > #include <iostream>
> > > #include <ostream>
> > > #include <iterator>
> > > #include <algorithm>
>
> > > int main()
> > > {
> > > Array<5> items;
> > > std::copy( items.data, items.data+5,
> > > std::ostream_iterator<int>( std::cout, "\n" ) );
> > > /* do stuff with items */
> > > return 0;
>
> > > }
>
> > > Note, however, that the computation is not really done at compile time since
> > > the static functions are executed at runtime. The following fixes at least
> > > that:
>
> > > template <int I>
> > > struct Item {
>
> > > static
> > > void put ( int* where ) {
> > > Item<I-1>::put( where );
> > > where[I] = Item<I>::value;
> > > }
>
> > > static int const value =
> > > Item<I-1>::value + Item<I-2>::value;
>
> > > };
>
> > > template <>
> > > struct Item<0> {
>
> > > static
> > > void put ( int* where ) {
> > > where[0] = Item<0>::value;
> > > }
>
> > > static int const value = 1;
>
> > > };
>
> > > template <>
> > > struct Item<1> {
>
> > > static
> > > void put ( int* where ) {
> > > where[0] = Item<0>::value;
> > > where[1] = Item<1>::value;
> > > }
>
> > > static int const value = 1;
>
> > > };
>
> > > template < int N >
> > > struct Array {
>
> > > Array() {
> > > Item<N-1>::put( data );
> > > }
>
> > > int data[N];
>
> > > };
>
> > > #include <iostream>
> > > #include <ostream>
> > > #include <iterator>
> > > #include <algorithm>
>
> > > int main()
> > > {
> > > Array<5> items;
> > > std::copy( items.data, items.data+5,
> > > std::ostream_iterator<int>( std::cout, "\n" ) );
> > > /* do stuff with items */
> > > return 0;
>
> > > }
>
> > > The array itself is populated at runtime in the constructor of Array. I
> > > don't see a way to push that into compile time.
>
> > > Best
>
> > > Kai-Uwe Bux
>
> > Alright, so I'm getting a little closer and now I've at least got code
> > that compiles
>
> > struct Bar
> > {
> > int X() { return -1; }
>
> > };
>
> > template <int I>
> > struct Foo : Bar {};
>
> > template <>
> > struct Foo<0>
> > {
> > int X() { return 0; }
>
> > }
>
> > template <int N>
> > class Array
> > {
> > Bar data[N];
>
> > }
>
> > int main()
> > {
> > // Now I need to figure out how doing this ...
> > Array<3> array1;
>
> > // ... can essentially result in this
> > Bar array2[3] = {Foo<0>(), Foo<1>(), Foo<2>()};
>
> > }
>
> So after more experimentation and testing I've got this working and
> the solution is pretty straight forward
>
> struct Bar
> {
> virtual int X() { return -1; }
>
> };
>
> template <int I>
> struct Foo : Bar
> {
> virtual int X() { return I; }
>
> };
>
> template <>
> struct Foo<0> : Bar
> {
> virtual int X() { return 50; }
>
> };
>
> template <int N>
> class Array
> {
> public:
> Array() { Init(m_data); }
>
> Bar* operator[] (int i) { return m_data[i]; }
>
> protected:
> friend class Array<N+1>;
>
> // Recursively initialize our array
> static void Init(Bar** data)
> {
> data[N] = new Foo<N>();
> Array<N-1>::Init(data);
> }
>
> Bar* m_data[N+1];
>
> };
>
> template <>
> class Array<0>
> {
> protected:
> friend class Array<1>;
>
> // Stop the recursion
> static void Init(Bar** data)
> {
> data[0] = new Foo<0>();
> }
>
> };
>
> int main()
> {
> Array<3> array;
> for (int i=0; i <= 3; i++)
> {
> printf("value: %d\n", array[i]->X());
> }
>
> }
>
> value: 50
> value: 1
> value: 2
> value: 3- ??????? -
>
> - ??????? -

Be more correct ,you should wirte as following
////////////
template <int I>
struct Foo : public Bar
{
virtual int X() { return I; }
};

template <>
struct Foo<0> : public Bar
{
virtual int X() { return 50; }


};
////////////