[英]Pattern matching style in C++?
我喜欢Haskell样式模式匹配。
我的C ++代码如下:
ObjectPtr ptr;
if(ptr.isType<Foo>()) { // isType returns a bool
Ptr<Foo> p = ptr.convertAs<Foo>(); // convertAs returns a Ptr<Foo>
......
}
if(ptr.isType<Bar>()) {
Ptr<Bar> p = ptr.convertAs<Bar>();
......
}
现在,我可以定义一些宏来简化此过程吗? 我已经考虑了一段时间,但无法进一步简化它。
谢谢!
dynamic_cast
似乎dynamic_cast
您的要求
struct A {
virtual ~A() {}
};
struct B : struct A { ... };
struct C : struct A { ... };
A * a = new C;
if ( C * c = dynamic_cast<C*>( a ) ) {
c->someCfunc();
}
else if ( B * b = dynamic_cast<B*>( a ) ) {
b->someBfunc();
}
else {
throw "Don't know that type";
}
我喜欢Haskell样式模式匹配。
然后在Haskell中编写程序。
您想要做的是切换类型。 如果人们想避免使用虚函数,那是很常见的事情。 现在,后者是C ++中OO的全部基石。 如果要避免它们,为什么要用C ++编程?
至于为什么对此不满意:想象您有很多这样的代码
if(ptr.isType<Foo>()) ...
if(ptr.isType<Bar>()) ...
在您的代码中涂抹所有内容,然后有人来将Baz
添加到ptr
可能表示的可能类型中。 现在,您正在遍历庞大的代码库,试图找到所有您在其中切换了类型的地方,并试图找出需要向其添加Baz
的地方。
而且,正如墨菲(Furphy)所做的那样,当您完成操作时,也会附带Foz
作为类型添加。 (或者,再三考虑,如果墨菲有他的方法,那么在您没有完全添加Baz
的机会之前,它就会悄悄Baz
。)
尝试使用RTTI在C ++中模拟模式匹配样式是一个好主意,但它必然会有缺点,因为Haskell和Standard ML样式类型构造函数与C ++子类之间存在一些显着差异。 (注意:下面,我使用标准ML语法,因为我对此比较满意。)
a::b::c::ds
将列表的前三个元素绑定到a
, b
和c
,其余的列表中的ds
)。 在C ++中,您仍然必须深入研究实际的嵌套结构,除非您或其他人提出了比此处提出的复杂得多的宏。 datatype 'a option = NONE | SOME of 'a
datatype 'a option = NONE | SOME of 'a
定义了一种新类型: 'a option
。 构造函数NONE
和SOME
不是类型,它们分别是类型为'a option
和'a -> 'a option
。 在C ++中,当您定义诸如Foo
和Bar
类的子类来模拟类型构造函数时,您将获得新的类型。 SOME
这样的构造函数是一类函数,它们构造它们所属的数据类型的值。 例如, map SOME
具有类型'a list -> 'a option list
。 在C ++中,使用子类来模拟类型构造函数,您不会获得此功能。 最后,与以更典型的方式使用C ++多态相比,您是否从模拟模式匹配中获得了足够的收益? 是否值得使用宏使模拟模式匹配更简洁(同时使其他读取您的代码的人感到困惑)是否值得?
我们与他人合着了C ++模式匹配库,使您可以非常高效地进行模式匹配和类型分析。 名为Mach7的库已根据BSD许可发布,可在GitHub上找到: https : //github.com/solodon4/Mach7 。 您可以在此处找到视频,海报,幻灯片,论文以及源代码。 目前,它支持GCC 4.4 +,Clang 3.4+和Visual C ++ 2010+。 通过针对其存储库提交GitHub问题,随时提出有关该库的问题。
我假设您的Ptr
模板具有NULL指针的概念。
ObjectPtr ptr;
if(Ptr<Foo> p = ptr.convertAs<Foo>()) { // convertAs returns a NULL pointer if the conversion can't be done.
......
}
if(Ptr<Bar> p = ptr.convertAs<Bar>()) {
......
}
但是,正如其他人指出的那样,打开类型通常是在C ++中做错事情的标志。 您应该考虑使用虚函数。
一个想法,这个宏正是您想要的:
#define DYN_IF(dest_type, dest_ptr, src_ptr) \
if((src_ptr).isType<dest_type>()) \
if(int dest_type##dest_ptr = 1) \
for(Ptr<dest_type> dest_ptr = (src_ptr).convertAs<dest_type>(); \
dest_type##dest_ptr; \
dest_type##dest_ptr=0)
用法:
ObjectPtr ptr;
DYN_IF(Foo, foo_ptr, ptr) {
// foo_ptr is Ptr<Foo>
}
DYN_IF(Bar, bar_ptr, ptr) // Works without braces too for single statement
// bar_ptr is Ptr<Bar>
我不会在代码中推荐这类东西,以免被其他人阅读,但是由于您提到了“宏”一词,所以……
另外,我不会假装这与Haskell / OCaml样式中的模式匹配有关。 如果您想要一种语言,其语义类似于C ++(很好,有点)并且是真正的模式匹配,请检查Scala。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.