使用部分模板特化来选择基类

时间:2016-04-15 21:32:16

标签: c++ templates c++11

我对下面尝试使用的一些高级模板技术感到陌生,所以我怀疑我的术语可能不太正确。我有一个Box基类型和几个继承自Box的类。我试图根据模板参数构建特定子类的实例。

这是Box<T>类型。 Convert函数可以使用返回类型U的函数创建新的Box<U>

template<typename T>
class Box : public std::enable_shared_from_this<Box<T>> {
 public:

  // Box<T> --> Box<U>
  template <typename Func>
  auto Convert(Func f) -> std::shared_ptr<Box<decltype(f(std::declval<T>()))>>;

  virtual void Print() {
    std::cout << "box" << std::endl;
  }
};

我可以像这样创建一个新的Box<int>类型:

auto box = std::shared_ptr<Box<int>>(new Box<int>());

要转换为另一种类型,我们返回一个类型为ConvertedBox的子类(实际上我们这样做是因为我们正在懒惰地应用该函数)。

template<typename T, typename U, typename Func>
class ConvertedBox : public Box<T> {
 public:
  ConvertedBox(typename std::shared_ptr<Box<U>> box, Func func) :
    box_(box), func_(func)
  {}

  virtual void Print() {
    std::cout << "converted box" << std::endl;
  }

 private:
  std::shared_ptr<Box<U>> box_;
  Func func_;
};

此处构造子类实例的方法。

// implementation of convert
template <typename T>
template <typename Func>
auto Box<T>::Convert(Func f) -> std::shared_ptr<Box<decltype(f(std::declval<T>()))>>
{
    using ReturnType = decltype(f(std::declval<T>()));
    auto p = new ConvertedBox<ReturnType, T, Func>(this->shared_from_this(), f);
    return std::shared_ptr<Box<ReturnType>>(p);
}

现在,我可以使用以下调用构建新的Box<U>

auto converted_float_box = box->Convert([](int v) -> float {
  return (float)v;
});

我希望能够做的是根据所应用的函数类型专门化Box<>基类。例如,如果我像这样转换为Box<std::pair<int, int>>

auto converted_pair_box = box->Convert([](int v) -> std::pair<int, int> {
  return std::make_pair(v, v);
});

我希望能够在仅Box<std::pair<K, V>>可用的结果上调用函数(我在这里使用print作为示例。在实践中,专业化很复杂)。

converted_pair_box->PairOnlyPrint();

我试图在Box上专注std::pair<K,V>,但没有运气。

template<typename K, typename V>
class PairBox : public Box<std::pair<K, V>> {
 public:
  void PairOnlyPrint() {
    std::cout << "only pair box" << std::endl;
  };
};

编译器仍在解析为Box<>,因此PairOnlyPrint不可用。有没有办法实现这个目标?

编辑1:正如所指出的,Convert不是免费功能。

1 个答案:

答案 0 :(得分:1)

您的class PairBox不是专业化,专业化将是:

template<typename K, typename V>
class Box<std::pair<K, V>>: public std::enable_shared_from_this<Box<std::pair<K, V>>> {
 public:

  // Box<T> --> Box<U>
  template <typename Func>
  auto Convert(Func f)
  -> std::shared_ptr<Box<decltype(f(std::declval<std::pair<K, V>>()))>>;

  virtual void Print() { std::cout << "pair box" << std::endl; }
  void PairOnlyPrint() { std::cout << "only pair box" << std::endl; };
};