how to instantiate array of objects knowing its indices at compiletime?

  • Thread starter Christof Warlich
  • Start date
C

Christof Warlich

Hi,

the subject says it all: I need to instantiate an array of objects
where each object "knows" its arrary index. So far, this is easy
as long as index is not a compile-time constant:

class Elements {
public:
Elements():
index(maxIndex) {
maxIndex++;
}
const unsigned int index;
private:
static unsigned int maxIndex;
};
unsigned int Elements::maxIndex = 0;
Elements array[5];

#include <stdio.h>
template<unsigned int x> struct Test {
};
int main(void) {
printf("%d\n", array[4].index);
printf("%d\n", array[2].index);
// No way to create an instance
// of Test<> with index.
}

The point is that I need to use index inside Element as a template
parameter constant, i.e index must be known for each Element instance
at compile time already.

Soemthing like this does work, but does not help as access to the
instances of Element cannot be done in a unique fashion by just
providing index:

template<unsigned int i> struct Array {
class Element {
public:
static const unsigned int index = i;
};
static Array<i - 1> array;
};
template<> struct Array<0> {
class Element {
public:
static const unsigned int index = 0;
};
};

#include <stdio.h>
template<unsigned int x> struct Test {
};
int main(void) {
printf("%d\n", Array<4>::Element::index);
printf("%d\n", Array<4>::Array<3>::Array<2>::Element::index);
Test<Array<4>::Array<3>::Element::index> test;
}

Any ideas how this problem could be solved?

Thanks for any help,

Christof
 
C

Christof Warlich

Victor said:
But that would make every Element a unique type (at the first glance,
anyway)! And that would mean you can't convert between them (unless you
make them all descendants of each other, which is ugly) or put them all
in the same collection/container...

You are right, but I could live with that, i.e. I do not need to convert
between them.

But what I need is some usable indexing:
Array<4>::Array<3>::Array<2>::Element::index is not a working solution
to access the value of index 2.
 
C

Christof Warlich

Victor said:
OK, I thought of something, but this might be more complicated than you
need: ......
int main() {
ArrayOf<10,int> myArrayOf10ints;

for (int i = 0; i < 10; ++i)
myArrayOf10ints = i+42;

for (int j = 3; j < 8; ++j)
std::cout << "# " << j;
std::cout << " is " << myArrayOf10ints[j] << std::endl;
}


Hi Victor,

thanks a lot for your help and sorry for the very late reply.
Unfortunately, this is not solving my problem of getting compile-time
constants by index.

Again, to illustrate what I'd need to do, I've slightly extended your
example. The key is to be able to pass the "array" value as a template
parameter, whatever object "array" might be:

......
template <unsigned int x> struct Test {
};
int main() {
ArrayOf<10,int> myArrayOf10ints;

for (int i = 0; i < 10; ++i)
myArrayOf10ints = i+42;

for (int j = 3; j < 8; ++j) {
std::cout << "# " << j;
std::cout << " is " << myArrayOf10ints[j] << std::endl;
}
Test test<myArrayOf10ints[5]>;
}

$ g++ constArray.cc
constArray.cc: In function 'int main()':
constArray.cc:58: error: 'myArrayOf10ints' cannot appear in a
constant-expression
constArray.cc:58: error: an array reference cannot appear in a
constant-expression
constArray.cc:58: error: template argument 1 is invalid
constArray.cc:58: error: invalid type in declaration before ';' token

It's clear to me that this cannot compile: The "array" must be
a compile time constant itself. My second example in the first
post fulfilled this requirement, but only at the cost of the
clumsy access, i.e.

Test<Array<4>::Array<3>::Element::index> test;

to acess the 3rd element, while I would need a solution where it
is sufficient to just pass in a 3 to get the 3rd element.

Note that logically, the index from my (second) example of my initial
post would correspond to the array values from your example. Therefore,
my example may have been a bit confusing as I was choosing my "array"
values to be equal to the index of that "array". This was due to my
original intention of knowing an instance's array index inside the
instance. But more generally, the problem boils down to:

template<unsigned int i> struct Array {
class Element {
public:
static const unsigned int value = i + 42;
};
static Array<i - 1> array;
};
template<> struct Array<0> {
class Element {
public:
static const unsigned int value = 42;
};
};

#include <stdio.h>
template<unsigned int x> struct Test {
};
int main(void) {
printf("%d\n", Array<4>::Element::value);
printf("%d\n", Array<4>::Array<3>::Array<2>::Element::value);
Test<Array<4>::Array<3>::Element::value> test;
}

Anyhow, maybe a solution for this problem simply does not exist.

Cheers,

Christof
 
C

courpron

Victor said:
OK, I thought of something, but this might be more complicated than you
need: .....
int main() {
   ArrayOf<10,int> myArrayOf10ints;
   for (int i = 0; i < 10; ++i)
      myArrayOf10ints = i+42;

   for (int j = 3; j < 8; ++j)
      std::cout << "# " << j;
      std::cout << " is " << myArrayOf10ints[j] << std::endl;
}

Hi Victor,

thanks a lot for your help and sorry for the very late reply.
Unfortunately, this is not solving my problem of getting compile-time
constants by index.

Again, to illustrate what I'd need to do, I've slightly extended your
example. The key is to be able to pass the "array" value as a template
parameter, whatever object "array" might be:

.....
template <unsigned int x> struct Test {};

int main() {
    ArrayOf<10,int> myArrayOf10ints;

    for (int i = 0; i < 10; ++i)
       myArrayOf10ints = i+42;

    for (int j = 3; j < 8; ++j) {
       std::cout << "# " << j;
       std::cout << " is " << myArrayOf10ints[j] << std::endl;
    }
    Test test<myArrayOf10ints[5]>;

}

$ g++ constArray.cc
constArray.cc: In function 'int main()':
constArray.cc:58: error: 'myArrayOf10ints' cannot appear in a
constant-expression
constArray.cc:58: error: an array reference cannot appear in a
constant-expression
constArray.cc:58: error: template argument 1 is invalid
constArray.cc:58: error: invalid type in declaration before ';' token

It's clear to me that this cannot compile: The "array" must be
a compile time constant itself. My second example in the first
post fulfilled this requirement, but only at the cost of the
clumsy access, i.e.

Test<Array<4>::Array<3>::Element::index> test;

to acess the 3rd element, while I would need a solution where it
is sufficient to just pass in a 3 to get the 3rd element.

Note that logically, the index from my (second) example of my initial
post would correspond to the array values from your example. Therefore,
my example may have been a bit confusing as I was choosing my "array"
values to be equal to the index of that "array". This was due to my
original intention of knowing an instance's array index inside the
instance. But more generally, the problem boils down to:

template<unsigned int i> struct Array {
     class Element {
       public:
         static const unsigned int value = i + 42;
     };
     static Array<i - 1> array;};

template<> struct Array<0> {
     class Element {
       public:
         static const unsigned int value = 42;
     };

};

#include <stdio.h>
template<unsigned int x> struct Test {};

int main(void) {
     printf("%d\n", Array<4>::Element::value);
     printf("%d\n", Array<4>::Array<3>::Array<2>::Element::value);
     Test<Array<4>::Array<3>::Element::value> test;

}

Anyhow, maybe a solution for this problem simply does not exist.


Hi,

**** CODE ****

#include <iostream>


template <int INDEX>
struct ComputeElement {
static const int value = INDEX + 42 ;
};


template < int I, int J=0 > // two int parameters needed to get the
correct index
struct ArraySize : public ComputeElement<J> {
typedef ArraySize< I, J+1 > next;
};

template < int J >
struct ArraySize< J, J > : public ComputeElement<J> {};


template < int INDEX, class T = ArraySize<10> >
struct Array {
static const int value = Array < INDEX-1,
typename T::next >::value;
};

template < class T >
struct Array < 0, T > {
static const int value = T::value;
};


int main()
{
std::cout << Array< 0 >::value ; // first element
std::cout << Array< 9 >::value ; // last element
}

**** /CODE ****

Alexandre Courpron.
 
C

Christof Warlich

Hi,

**** CODE ****

#include <iostream>


template <int INDEX>
struct ComputeElement {
static const int value = INDEX + 42 ;
};


template < int I, int J=0 > // two int parameters needed to get the
correct index
struct ArraySize : public ComputeElement<J> {
typedef ArraySize< I, J+1 > next;
};

template < int J >
struct ArraySize< J, J > : public ComputeElement<J> {};


template < int INDEX, class T = ArraySize<10> >
struct Array {
static const int value = Array < INDEX-1,
typename T::next >::value;
};

template < class T >
struct Array < 0, T > {
static const int value = T::value;
};


int main()
{
std::cout << Array< 0 >::value ; // first element
std::cout << Array< 9 >::value ; // last element
}

**** /CODE ****

Alexandre Courpron.
Hi Alexandre,

wow, this is genius! It's exactly doing what I need, though I have
to admit that I'll need some time digesting the code to fully
understand how it works.

For now thanks a lot,

Christof
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top