Metaprogramming question

P

PengYu.UT

I want to define a bunch of class like the following.
In general, test<n> have n integer arguments. It has a member function
"doit", which returns

l_i for 0 <= i < l
0 for i == l or 2l + 1
-l_(2n - i) for l+1 <= i < 2l

I'm wondering how to define these test* classes using metaprogramming?
Would you please let me know, if you have any ideas.

Thanks,
Peng

#include <vector>
#include <cassert>
#include <iostream>

class test1{
public:
test1(int l0){
_v.push_back(l0);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return 0;
case 2:
return -_v[0];
case 3:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

class test2{
public:
test2(int l0, int l1){
_v.push_back(l0);
_v.push_back(l1);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return _v[1];
case 2:
return 0;
case 3:
return -_v[1];
case 4:
return -_v[0];
case 5:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

int main(int argc, char *argv[]) {
test1 t1(1);
for(int i = 0; i < 2 * 1 + 2; ++ i){
std::cout << t1.doit(i) << std::endl;
}
test2 t2(1,2);
for(int i = 0; i < 2 * 2 + 2; ++ i){
std::cout << t2.doit(i) << std::endl;
}
}
 
D

Dave Townsend

I want to define a bunch of class like the following.
In general, test<n> have n integer arguments. It has a member function
"doit", which returns

l_i for 0 <= i < l
0 for i == l or 2l + 1
-l_(2n - i) for l+1 <= i < 2l

I'm wondering how to define these test* classes using metaprogramming?
Would you please let me know, if you have any ideas.

Thanks,
Peng

#include <vector>
#include <cassert>
#include <iostream>

class test1{
public:
test1(int l0){
_v.push_back(l0);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return 0;
case 2:
return -_v[0];
case 3:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

class test2{
public:
test2(int l0, int l1){
_v.push_back(l0);
_v.push_back(l1);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return _v[1];
case 2:
return 0;
case 3:
return -_v[1];
case 4:
return -_v[0];
case 5:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

int main(int argc, char *argv[]) {
test1 t1(1);
for(int i = 0; i < 2 * 1 + 2; ++ i){
std::cout << t1.doit(i) << std::endl;
}
test2 t2(1,2);
for(int i = 0; i < 2 * 2 + 2; ++ i){
std::cout << t2.doit(i) << std::endl;
}
}

Could you do something like:

template<unsigned int N>
class Test : public Test<N-1>
{
public:
Test<N>( );
Test<N>(int n1)
Test<N>(int n1, int n2)
Test<N>(int n1, int n2, int n3)
etc .
int doit( int n )
{
// some formula...to compute the value....
}
vector<int> _args;

};

// specialization to end the defintion chain.
template<>
class Test<0>
{
int doit( int n );

};
Test<N>(int n1 )
:Test<N-1>( )
{
_args.push_back(n1);
}

Test<N>(int n1 , int n2)
:Test<N-1>(n2)
{
_args.push_back(n2);

}

Test<N>(int n1 , int n2, int n3)
:Test<N-1>(n2,n3 )
{
_args.push_back(n3);

}

As far as I know, there isn't a way to parameterize the number of arguments
for the
template member functions - although there might be something in boost you
could
use. If you have a fairly bounded number for N, you can just enumerate all
possibilities
by including constructors for Test<N> with 0 through N arguments.
 
G

Greg

I want to define a bunch of class like the following.
In general, test<n> have n integer arguments. It has a member function
"doit", which returns

l_i for 0 <= i < l
0 for i == l or 2l + 1
-l_(2n - i) for l+1 <= i < 2l

I'm wondering how to define these test* classes using metaprogramming?
Would you please let me know, if you have any ideas.

Thanks,
Peng

#include <vector>
#include <cassert>
#include <iostream>

class test1{
public:
test1(int l0){
_v.push_back(l0);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return 0;
case 2:
return -_v[0];
case 3:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

class test2{
public:
test2(int l0, int l1){
_v.push_back(l0);
_v.push_back(l1);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return _v[1];
case 2:
return 0;
case 3:
return -_v[1];
case 4:
return -_v[0];
case 5:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

int main(int argc, char *argv[]) {
test1 t1(1);
for(int i = 0; i < 2 * 1 + 2; ++ i){
std::cout << t1.doit(i) << std::endl;
}
test2 t2(1,2);
for(int i = 0; i < 2 * 2 + 2; ++ i){
std::cout << t2.doit(i) << std::endl;
}
}

First, please avoid using the lowercase "L" as a variable name or to
differentiate variable names. It's quite confusing to separate 10 from
the l0 for instance. Also I had trouble with these formulas:

-l_(2n - i)
l_i

But based on the program provided I think I figured it out. Anyway, the
following program should be enough to get you started:

template<int N>
struct Integer
{
static const int value = N;
typedef Integer<N+1> next;
};

template <class N, class C >
struct Test
{
static const int value = C::value < N::value ?
C::value :
-1-(2*N::value - C::value);
};

// Integer class is needed for this specialization:
template <int N>
struct Test< Integer<N>, Integer<2*N+1> >
{
static const int value = 0;
};

template <class N>
struct Test<N, N>
{
static const int value = 0;
};

template <class N, class C>
void DoIt( const Test<N, C> )
{
std::cout << Test<N, C>::value << " ";

DoIt( Test<N, typename C::next >() );
}

template <int N>
void DoIt( const Test<Integer<N>, Integer<N*2+1> > )
{
std::cout << Test<Integer<N>, Integer<N*2+1> >::value << " ";
}

int main()
{
DoIt( Test< Integer<1>, Integer<0> >());
std::cout << std::endl;
DoIt( Test< Integer<2>, Integer<0> >());
std::cout << std::endl;
}

Output:
0 0 -1 0
0 1 0 -2 -1 0

Greg
 
G

Greg

Greg said:
....
First, please avoid using the lowercase "L" as a variable name or to
differentiate variable names. It's quite confusing to separate 10 from
the l0 for instance. Also I had trouble with these formulas:

-l_(2n - i)
l_i

But based on the program provided I think I figured it out. Anyway, the
following program should be enough to get you started:

template<int N>
struct Integer
{
static const int value = N;
typedef Integer<N+1> next;
};

template <class N, class C >
struct Test
{
static const int value = C::value < N::value ?
C::value :
-1-(2*N::value - C::value);
};
....
int main()
{
DoIt( Test< Integer<1>, Integer<0> >());
std::cout << std::endl;
DoIt( Test< Integer<2>, Integer<0> >());
std::cout << std::endl;
}

Output:
0 0 -1 0
0 1 0 -2 -1 0

Greg

Of course as soon as I post my program I notice an error. Change:

static const int value = C::value < N::value ?
C::value :
-1-(2*N::value - C::value);

to:

static const int value = C::value < N::value ?
C::value + 1:
-1-(2*N::value - C::value);

for the output:

1 0 -1 0
1 2 0 -2 -1 0

which at least matches the original program's output.

Greg
 
R

ravips

Dave said:
I want to define a bunch of class like the following.
In general, test<n> have n integer arguments. It has a member function
"doit", which returns

l_i for 0 <= i < l
0 for i == l or 2l + 1
-l_(2n - i) for l+1 <= i < 2l

I'm wondering how to define these test* classes using metaprogramming?
Would you please let me know, if you have any ideas.

Thanks,
Peng

#include <vector>
#include <cassert>
#include <iostream>

class test1{
public:
test1(int l0){
_v.push_back(l0);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return 0;
case 2:
return -_v[0];
case 3:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

class test2{
public:
test2(int l0, int l1){
_v.push_back(l0);
_v.push_back(l1);
}
int doit(int i){
switch(i){
case 0:
return _v[0];
case 1:
return _v[1];
case 2:
return 0;
case 3:
return -_v[1];
case 4:
return -_v[0];
case 5:
return 0;
default:
assert(0);
}
}
private:
std::vector<int> _v;
};

int main(int argc, char *argv[]) {
test1 t1(1);
for(int i = 0; i < 2 * 1 + 2; ++ i){
std::cout << t1.doit(i) << std::endl;
}
test2 t2(1,2);
for(int i = 0; i < 2 * 2 + 2; ++ i){
std::cout << t2.doit(i) << std::endl;
}
}
With Metatemplates this may not be possible..to generate functions with
var args...
U can simply use a single template class with variable no. of args
passed to the constructor.
 
J

Jon Slaughter

Greg said:
(e-mail address removed) wrote:

First, please avoid using the lowercase "L" as a variable name or to
differentiate variable names. It's quite confusing to separate 10 from
the l0 for instance. Also I had trouble with these formulas:

yessim massa

<snip>
 
J

Jon Slaughter

Dave Townsend said:
As far as I know, there isn't a way to parameterize the number of
arguments
for the
template member functions - although there might be something in boost you
could
use. If you have a fairly bounded number for N, you can just enumerate
all
possibilities
by including constructors for Test<N> with 0 through N arguments.

There is a preprocessor extension in boost that you can use to generate code
that is repeatative such as a series of "variable" parameters of some type.
I don't think this is a very efficient method though but it seems it will
get the job done.

http://www.boost.org/libs/preprocessor/doc/index.html

Jon
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top