在非虚拟多态类中减少用于基础的样板到派生委派

时间:2017-11-25 20:56:33

标签: c++ c++11 templates polymorphism

考虑一个封闭的 1 类层次结构,如下所示:

class B {...}; 
class D1 final : public B {...};
class D2 final : public B {...};

其中B是一个抽象的 2 基类,D1D2是它的派生类。

由于实施限制或设计,这些类中没有一个具有任何virtual方法,但B上的成员函数在D1D2中具有不同的实现只需委派通过对派生类型进行运行时检查来实现最实际的派生类型,如下所示:

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最终通过D1D2(因为两者都有to_string方法)。在C ++ 11中,我没有看到一种等效的简洁方式来表达这一点。

有什么想法吗?

当然,您可以使用宏来复制非泛型宏并将其传递给2参数delegate方法(对D1D2采用单独的仿函数)但我想避免使用宏。

1 这里关闭意味着B的派生类集是固定的并且在运行时已知。

2 摘要概念但不是&#34;纯virtual&#34;感。也就是说,这个类不应该直接实例化 - 唯一有意义的整个对象是它的派生类。各种构造函数都是protected来强制执行此操作。

1 个答案:

答案 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)();
  }