[英]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.