ok, I use your Container structs, combine them with XCont, and define the XContainer you want:
// a (bit-)LIST is an int that contains the value (TAIL<<1|HEAD),
// where TAIL is a LIST, and HEAD is either 1 or 0.
// while iterating through the LIST from right,
// SHL counts how far each consumed HEAD has to be shifted left,
// back to its original position.
template<int TAIL,int HEAD,int SHL>
struct XCont;
//the empty LIST
template<int SHL>
struct XCont<0,0,SHL>{};
//HEAD equals 0, so we just recurse through the TAIL.
template<int TAIL,int SHL>
struct XCont<TAIL,0,SHL>:public XCont< (TAIL>>1) , (TAIL&1) , (SHL+1) >{};
//HEAD equals 1, so we do like above, but we have to append Container< (1<<SHL) >.
template<int TAIL,int SHL>
struct XCont<TAIL,1,SHL>:public XCont< (TAIL>>1) , (TAIL&1) , (SHL+1) >,public Container< (1<<SHL) >{};
template<int E>
struct XContainer:public XCont< (E>>1) , (E&1) , (0) >{};
It works like this:
- The bitmask will be interpreted as LIST of bits from right to left (least significant bit first.
- We iterate through the bits by bit-shifting (>>) the LIST.
- The LIST is represented in functional programming style as tuple of HEAD and TAIL, where HEAD is the first element and TAIL is the LIST of remaining elements without that HEAD.
- Whenever we find a 1-bit as HEAD, we want to recalculate its bit-position, so we count that via SHL. Of course, there are other approaches, too, like bitshifting a mask over the list and testing its value on 0 and non-0.
These do equal:
- XContainer< EBOOL | EFLOAT | EINT >
- XContainer< 0x04 | 0x02 | 0x01 >
- XContainer< 0x07 >
- XCont< (0x07>>1) , (0x07&1) , (0) >
- XCont< ((EBOOL | EFLOAT | EINT) >>1) , (EINT) , (0) >
- XCont< ((EBOOL | EFLOAT) >>1) , (EINT) , (0) >
- XCont< ((EBOOL | EFLOAT) >>1) , (EINT>>0) , (0) >
- XCont< TAIL,1,SHL >, where...
- TAIL = ((EBOOL | EFLOAT) >>1)
- 1 = (EINT>>0)
- SHL = (0)
- EINT = (1 << SHL)
- XCont< TAIL>>1,TAIL&1,SHL+1 > ++ Container< (1 << SHL) >
- ...
- XCont< 0,0,(3) > ++ Container< (1<<(2)) > ++ Container< (1<<(1)) > ++ Container< (1<<(0)) >
- XCont< 0,0,(3) > ++ Container< EBOOL > ++ Container< EFLOAT > ++ Container< EINT >
C++ templates behave like pattern-matching in Haskell.
So, to me, it is easier to think about it in a simple style of Haskell functions without any fancy Haskell things. If anyone is curious:
xcontainer :: Int -> String
xcontainer(e) = "struct XContainer:" ++ (
xcont( (e .>>. 1) , (e .&. 1) , (0) )
) ++ "{}"
xcont :: (Int,Int,Int) -> String
xcont( 0,0,shl) = "public XCont<0,0," ++ show(shl) ++ ">"
xcont(tail,0,shl) = ( xcont( (tail .>>. 1) , (tail .&. 1) , (shl+1) )
)
xcont(tail,1,shl) = ( xcont( (tail .>>. 1) , (tail .&. 1) , (shl+1) )
) ++ "," ++ container(1 .<<. shl)
container :: Int -> String
container(e) = "public Container<" ++ show(e) ++ ">"
(This is valid Haskell but in a non-haskell writing style.)