Sign in to follow this  
lhead

Template Metaprogramming - infinite IfElse

Recommended Posts

The following is a nice trick in template meta programming
template<
    bool b,
    typename A,
    typename B
> struct IfElse {
    typedef A Result;
};


template<
    typename A,
    typename B
> struct IfElse<false, A, B> {
    typedef B Result;
};

The following would be so nice, but it simply doesn't work :( I know I could instead use the first one with a nested argument list, but i would really like to know why the second one doesn't work! (I'm using gcc 3.4.2 on WinXP)
template<
    bool a,  // true
    typename A
> struct If
{
    template<typename B> struct Else {
        typedef  A  Result;
    };
    
    template<bool b, typename B> struct ElseIf : If<true, A> {
    };
};


template<
    typename A
> struct If<false, A>
{
    template<typename B> struct Else {
        typedef  B  Result;
    };
    
    template<bool b, typename B> struct ElseIf : If<b, B> {
        //using If<b, B>::template ElseIf;
    };
};


//                                                                     testing
//-----------------------------------------------------------------------------

struct A {static char* foo() { return "A"; } };
struct B {static char* foo() { return "B"; } };
struct C {static char* foo() { return "C"; } };
struct D {static char* foo() { return "D"; } };
struct E {static char* foo() { return "E"; } };
struct F {static char* foo() { return "F"; } };
struct G {static char* foo() { return "G"; } };
struct H {static char* foo() { return "H"; } };
struct I {static char* foo() { return "I"; } };

template<
    bool b0=true, bool b1=true, bool b2=true, bool b3=true,
    bool b4=true, bool b5=true, bool b6=true, bool b7=true
> struct SwitchCase
{
    typedef   typename If<b0, A>
        ::template ElseIf<b1, B>
        ::template ElseIf<b2, C>
        ::template ElseIf<b3, D>
        ::template ElseIf<b4, E>
        ::template ElseIf<b5, F>
        ::template ElseIf<b6, G>
        ::template ElseIf<b7, H>
        ::template Else<I>::Result  Result;
};




template<
    bool b0=true, bool b1=true, bool b2=true
    bool b3=true, bool b4=true
> void run_5()
{
    cout << endl;
    
    cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 0>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 1>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 0, 1, 0>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 0, 1, 1>::foo() << " ";
    
    cout << SwitchCase<b0, b1, b2, b3, b4, 1, 0, 0>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 1, 0, 1>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 1, 1, 0>::foo() << " ";
    cout << SwitchCase<b0, b1, b2, b3, b4, 1, 1, 1>::foo() << " ";
};

template<
    bool b0=true, bool b1=true, bool b2=true
> void run_2()
{
    cout << endl;
    run_5<b0, b1, 0, 0, 0>(); cout << " ";
    run_5<b0, b1, 0, 0, 1>(); cout << endl;
    run_5<b0, b1, 0, 1, 0>(); cout << " ";
    run_5<b0, b1, 0, 1, 1>(); cout << endl;
    
    run_5<b0, b1, 1, 0, 0>(); cout << " ";
    run_5<b0, b1, 1, 0, 1>(); cout << endl;
    run_5<b0, b1, 1, 1, 0>(); cout << " ";
    run_5<b0, b1, 1, 1, 1>(); cout << endl;
};

void run_0()
{
    cout << endl;
    run_2<0, 0>(); cout << endl;
    run_2<0, 1>(); cout << endl;
    cout << endl;
    run_2<1, 0>(); cout << endl;
    run_2<1, 1>(); cout << endl;
};
   



Share this post


Link to post
Share on other sites
Nope, it wasn't what I originally(1) suspected. It was just sloppy syntax, and obviously not reading what the compiler says!!!!!!!

1. Insert this to your If<a,A> definition:
typedef A Result;

2. Use Result when referring to inner type: The following line:
std::cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 0>::foo() << " ";
should read:
std::cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 0>::Result::foo() << " ";

3. Function templates cannot have default template arguments. Your compiler should tell you that. And problably already did.


Sorry for being harsh, but I can't stand only a few things, one of them being: not reading your compiler errors.

---
(1) My previous post was deleted.

Share this post


Link to post
Share on other sites
sorry! sometimes I don't post the code that I actually use, but some modified one that I hope is better readable. And then I forget ro let the compiler run through the modified code.

The important part is the first passage.

I made some modifications to the testing part, and now get to the error message I want to reproduce. More or less this one.
error: no class template named `ElseIf' in `struct If< false, A>
::ElseIf< false, B>'

with this (modified) code


#include<iostream>
using namespace std;


template<
bool a, // true
typename A
> struct If
{
template<typename B> struct Else {
typedef A Result;
};

template<bool b, typename B> struct ElseIf : If<true, A> {
};
};


template<
typename A
> struct If<false, A>
{
template<typename B> struct Else {
typedef B Result;
};

template<bool b, typename B> struct ElseIf : If<b, B> {
//using If<b, B>::template ElseIf;
};
};


// testing
//-----------------------------------------------------------------------------

struct A {static char* foo() { return "A"; } };
struct B {static char* foo() { return "B"; } };
struct C {static char* foo() { return "C"; } };
struct D {static char* foo() { return "D"; } };
struct E {static char* foo() { return "E"; } };
struct F {static char* foo() { return "F"; } };
struct G {static char* foo() { return "G"; } };
struct H {static char* foo() { return "H"; } };
struct I {static char* foo() { return "I"; } };

template<
bool b0=true, bool b1=true, bool b2=true, bool b3=true,
bool b4=true, bool b5=true, bool b6=true, bool b7=true
> struct SwitchCase
{
typedef typename If<b0, A>
::template ElseIf<b1, B>
::template ElseIf<b2, C>
::template ElseIf<b3, D>
::template ElseIf<b4, E>
::template ElseIf<b5, F>
::template ElseIf<b6, G>
::template ElseIf<b7, H>
::template Else<I>::Result Result;
};




template<
bool b0=true, bool b1=true, bool b2=true,
bool b3=true, bool b4=true
> struct Run_5
{
static void go()
{
cout << endl;

cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 0>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 0, 0, 1>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 0, 1, 0>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 0, 1, 1>::Result::foo() << " ";

cout << SwitchCase<b0, b1, b2, b3, b4, 1, 0, 0>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 1, 0, 1>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 1, 1, 0>::Result::foo() << " ";
cout << SwitchCase<b0, b1, b2, b3, b4, 1, 1, 1>::Result::foo() << " ";
}
};


template<
bool b0=true, bool b1=true
> struct Run_2
{
static void go()
{
cout << endl;
Run_5<b0, b1, 0, 0, 0>::go(); cout << " ";
Run_5<b0, b1, 0, 0, 1>::go(); cout << endl;
Run_5<b0, b1, 0, 1, 0>::go(); cout << " ";
Run_5<b0, b1, 0, 1, 1>::go(); cout << endl;

Run_5<b0, b1, 1, 0, 0>::go(); cout << " ";
Run_5<b0, b1, 1, 0, 1>::go(); cout << endl;
Run_5<b0, b1, 1, 1, 0>::go(); cout << " ";
Run_5<b0, b1, 1, 1, 1>::go(); cout << endl;
}
};


void run_0()
{
cout << endl;
Run_2<0, 0>::go(); cout << endl;
Run_2<0, 1>::go(); cout << endl;
cout << endl;
Run_2<1, 0>::go(); cout << endl;
Run_2<1, 1>::go(); cout << endl;
};



int main() {
run_0();
}




I will now try the "typedef A Result". I guess I should then use 'Result' as template argument for the further declarations?

Share this post


Link to post
Share on other sites
Quote:
Original post by lhead
I will now try the "typedef A Result". I guess I should then use 'Result' as template argument for the further declarations?


Nope, it was only so that If<1, A>::Result would work.

The real solution would be to change inheritance to internal typedef (guess we can call that composition[smile]).

// for true
template<bool b, typename T>
struct ElseIf
{
typedef If<true, S> type;
};
// for false
template<bool b, typename T>
struct ElseIf
{
typedef If<b, T> type;
};

template<
bool b0=true, bool b1=true, bool b2=true, bool b3=true,
bool b4=true, bool b5=true, bool b6=true, bool b7=true
> struct SwitchCase
{
typedef typename If<b0, A>
::template ElseIf<b1, B>::type
::template ElseIf<b2, C>::type
::template ElseIf<b3, D>::type
::template ElseIf<b4, E>::type
::template ElseIf<b5, F>::type
::template ElseIf<b6, G>::type
::template ElseIf<b7, H>::type
::template Else<I>::Result Result;
};


Unfortunately I don't have a good explanation for this phenomena.

Share this post


Link to post
Share on other sites
das hab ich schon befürchtet also muss man unbedingt ein typedef zwischen die template-ebenen packen.

es funktioniert übrigens, und zwar mit korrektem Ergebnis! Also danke für den Tipp, und blöd daß es nicht auf die direkte Art funktioniert.

edit:
uh shit I'm really deranged. i'm writing in german!!
it means, more or less:
I was afraid I would need to put a typedef between the templates. Now I made a test, and it works - with the correct result, as you can see.

but it is not impossible that you understand some german. nevermind.. [solved]<- never do that




I H G G F F F F
E E E E E E E E

D D D D D D D D
D D D D D D D D

C C C C C C C C
C C C C C C C C

C C C C C C C C
C C C C C C C C



B B B B B B B B
B B B B B B B B

B B B B B B B B
B B B B B B B B

B B B B B B B B
B B B B B B B B

B B B B B B B B
B B B B B B B B




A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A



A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A

A A A A A A A A
A A A A A A A A





[Edited by - lhead on November 27, 2006 12:27:12 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by lhead
das hab ich schon befürchtet also muss man unbedingt ein typedef zwischen die template-ebenen packen.

es funktioniert übrigens, und zwar mit korrektem Ergebnis! Also danke für den Tipp, und blöd daß es nicht auf die direkte Art funktioniert.


Yeah, right.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this