考虑一个封闭的 1 类层次结构,如下所示:
class B {...};
class D1 final : public B {...};
class D2 final : public B {...};
其中B
是一个抽象的 2 基类,D1
和D2
是它的派生类。
由于实施限制或设计,这些类中没有一个具有任何virtual
方法,但B
上的成员函数在D1
和D2
中具有不同的实现只需委派通过对派生类型进行运行时检查来实现最实际的派生类型,如下所示:
class B {
bool isD1;
protected:
B(bool isD1) : isD1{isD1} {}
public:
std::string to_string() {
return isD1 ? static_cast<D1*>(this)->to_string() : static_cast<D2*>(this)->to_string();
}
}
class D1 final : public B {
public:
D1() : B(true) {}
std::string to_string() { // D1 specific implementation ... }
}
class D2 final : public B {
public:
D2() : B(false) {}
std::string to_string() { // D2 specific implementation ... }
}
此处to_string
上的B
方法只是检查B
的派生类型是D1
还是D2
,并调用相应的方法(也是在两种情况下都称为to_string
。
冷却。
现在想象还有10种方法,比如B::to_string
。我可以在C ++ 11中做些什么来减少B
中的委托样板,而不需要使用宏?
在C ++ 14中,似乎合理的方法是通用委托机制,如:
class B {
...
template <typename F>
auto delegate(F&& f) -> decltype(f(D1{})) {
return isD1 : f(*static_cast<D1*>(this)) : f(*static_cast<D2*>(this));
}
std::string to_string() {
return delegate([](auto&& b){ return b.to_string(); });
}
}
此处[](auto&& b){ return b.to_string(); }
通用lambda最终通过D1
或D2
(因为两者都有to_string
方法)。在C ++ 11中,我没有看到一种等效的简洁方式来表达这一点。
有什么想法吗?
当然,您可以使用宏来复制非泛型宏并将其传递给2参数delegate
方法(对D1
和D2
采用单独的仿函数)但我想避免使用宏。
1 这里关闭意味着B
的派生类集是固定的并且在运行时已知。
2 摘要概念但不是&#34;纯virtual
&#34;感。也就是说,这个类不应该直接实例化 - 唯一有意义的整个对象是它的派生类。各种构造函数都是protected
来强制执行此操作。
答案 0 :(得分:1)
这个怎么样?
template <typename F1, typename F2>
auto delegate(F1 f1, F2 f2) -> decltype((D1{}.*f1)()) {
return isD1 ? (static_cast<D1*>(this)->*f1)() : (static_cast<D2*>(this)->*f2)();
}
std::string to_string() {
return delegate(&D1::to_string, &D2::to_string);
}
您还可以使其更强类型化:
template <typename Result>
Result delegate(Result (D1::*f1)(), Result (D2::*f2)()) {
return isD1 ? (static_cast<D1*>(this)->*f1)() : (static_cast<D2*>(this)->*f2)();
}