[英]c++ metaprogramming madness
考慮以下模板化數據結構
enum eContent{
EINT = 1,
EFLOAT = 2,
EBOOL = 4
};
template<int>
struct Container{
Container(){assert(false);} //woops, don't do that!
};
template<>
struct Container<EINT>{
Container():i(123){}
int i;
};
template<>
struct Container<EFLOAT>{
Container():f(123.456f){}
float f;
};
template<>
struct Container<EBOOL>{
Container():b(true){}
bool b;
};
<fancy macro goes here that creates me all kind of combinations including for example>
template<>
struct Container<EFLOAT | EBOOL>: public Container<EFLOAT>, public Container<EBOOL>{
Container():Container<EFLOAT>(),Container<EBOOL>(){}
};
</fancy macro>
這樣我就可以例如定義一個這樣的變量:
Container<EINT|EFLOAT|EBOOL> myVar;
我將如何定義這個奇特的宏?
為什么我要這個? 為了樂趣和學習元編程而去
好吧,首先, ||
是布爾值或運算符; 當您使用它時,它將始終為1
(或true
,而不是,但是當EINT
為int
時, true
總是提升為1
,在這種情況下),在您的代碼中等於EINT
因此,您的模板將始終實例化為Container<EINT>
。
想必您正在尋找按位或運算符, |
。 即使這樣,編譯器實際上仍將按位或值,所以您將獲得7
的值,這將導致使用未專業化的模板,這將失敗。
您到底想完成什么? 有多種方法可以使類型足夠靈活,以容納多種類型的多個數據,但是or運算符不會像在模板參數的上下文中那樣遠程執行任何操作。
enum eContent{
eInt = 1,
eFloat = 2,
eBool = 4
};
template<unsigned, unsigned>
struct Member {};
template<>
struct Member<eInt, eInt>{
Member():i(123){}
unsigned i;
};
template<>
struct Member<eFloat, eFloat>{
Member():f(123.456f){}
float f;
};
template<>
struct Member<eBool, eBool>{
Member():b(true){}
bool b;
};
template< unsigned members >
struct Container
: Member< members & eInt, eInt >
, Member< members & eFloat, eFloat >
, Member< members & eBool, eBool >
{};
int main()
{
Container< eFloat | eBool > c;
c.f; // OK
c.b; // OK
c.i; // !Nah
}
但是,我認為這對任何事情都沒有好處,實際上,這只是您所說的字面問題的解決方案。
如果您有一些實際的問題(您認為這可能是一個解決方案),請嘗試提出有關問題。
當然,除非只是玩耍或做作業。 :-)
干杯,……
PS:作為良好的C ++編程慣例,請將所有大寫名稱保留給宏,並且僅保留給宏。 這樣,您可以避免許多潛在的名稱沖突。 將ALL UPPERCASE用作常量是Java / Python / etc。 約定,某種程度上適合那些語言,但絕對不適合C ++。 它起源於早期的C,其中常量必須表示為宏。 所有大寫都是(並且是)用於宏的,而不是常量的-恩,除了布萊恩·科尼根(Brian Kernighan),但讓我們不探究歷史... ;-)
如果您在做我想做的事,請看一下boost::variant
,它確實在做您想做的事情。
好的,我使用您的Container結構,將它們與XCont結合在一起,然后定義所需的XContainer:
// 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) >{};
它是這樣的:
這些確實相等:
C ++模板的行為類似於Haskell中的模式匹配。 因此,對我來說,用一種簡單的Haskell函數樣式進行思考就比較容易,而無需花哨的Haskell事物。 如果有人好奇:
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) ++ ">"
(這是有效的Haskell,但采用非haskell寫作風格。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.