Ver*_*gon 11 c++ polymorphism lambda functional-programming c++11
一直以来,我发现自己做了这样的事情:
Animal *animal = ...
if (Cat *cat = dynamic_cast<Cat *>(animal)) {
...
}
else if (Dog *dog = dynamic_cast<Dog *>(animal)) {
...
}
else { assert(false); }
Run Code Online (Sandbox Code Playgroud)
一旦我看到C++ 11中的闭包,我想知道,这样的事情可能吗?
Animal *animal = ...
typecase(animal,
[](Cat *cat) {
...
},
[](Dog *dog) {
...
});
Run Code Online (Sandbox Code Playgroud)
实现类型规划本来应该很容易,但我一直遇到一个问题,它无法弄清楚函数的参数,所以它无法知道尝试使用dynamic_cast,因为很难推断出lambdas的参数.花了几天的时间搜索谷歌和SO,但终于想通了,所以我将在下面分享我的答案.
Ver*_*gon 10
感谢ecatmur在/sf/answers/935166431/上的回答,我能够从lambda中提取签名.完整的解决方案如下所示:
// Begin ecatmur's code
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename T>
struct get_signature_impl { using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type; };
template<typename R, typename... A>
struct get_signature_impl<R(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(&)(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(*)(A...)> { using type = R(A...); };
template<typename T> using get_signature = typename get_signature_impl<T>::type;
// End ecatmur's code
// Begin typecase code
template<typename Base, typename FirstSubclass, typename... RestOfSubclasses>
void typecase(
Base *base,
FirstSubclass &&first,
RestOfSubclasses &&... rest) {
using Signature = get_signature<FirstSubclass>;
using Function = std::function<Signature>;
if (typecaseHelper(base, (Function)first)) {
return;
}
else {
typecase(base, rest...);
}
}
template<typename Base>
void typecase(Base *) {
assert(false);
}
template<typename Base, typename T>
bool typecaseHelper(Base *base, std::function<void(T *)> func) {
if (T *first = dynamic_cast<T *>(base)) {
func(first);
return true;
}
else {
return false;
}
}
// End typecase code
Run Code Online (Sandbox Code Playgroud)
这里有一个示例用法:
class MyBaseClass {
public:
virtual ~MyBaseClass() { }
};
class MyDerivedA : public MyBaseClass { };
class MyDerivedB : public MyBaseClass { };
int main() {
MyBaseClass *basePtr = new MyDerivedB();
typecase(basePtr,
[](MyDerivedA *a) {
std::cout << "is type A!" << std::endl;
},
[](MyDerivedB *b) {
std::cout << "is type B!" << std::endl;
});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果有人有任何改进,请告诉我!