【问题标题】:Is it possible to use non-type template class with CRTP是否可以将非类型模板类与 CRTP 一起使用
【发布时间】:2021-10-22 12:13:40
【问题描述】:

我有以下 CRTP 基类:

template <typename T, template <typename> typename CRTPType>
  struct enable_crtp {
    auto underlying() -> T& { return static_cast<T&>(*this); }
    auto underlying() const -> const T& {
      return static_cast<const T&>(*this);
    }
  };

这种类型的类完美无缺:

template<typename Derived>
class BaseA : public enable_crtp<Derived, BaseA> {
public:
  void DoA() {
    this->underlying().DoAImpl();
  }
private:
  friend Derived;
};

class ImplA : public BaseA<ImplA> {
  void DoAImpl() {
    // do something 
  }

  friend BaseA<ImplA>;
};

但是有没有办法让它与非类型模板类一起工作?像这样的:

template<template<size_t> typename Derived>
class BaseB : public enable_crtp<Derived<size_t>, BaseB> {
                                         ^ compile error, template argument for non-type 
                                           template parameter must be an expression
  void DoB() {
    this->underlying().DoBImpl();
  }
}

对于真正的问题,我有一个IntegralImageCalculator,它将遍历图像像素以根据其i-th order 累加总和:

  template <size_t Order>
  class IntegralImageCalculator;

  template <>
  class IntegralImageCalculator<1> {
    void Iterate(cv::Mat& input) {
      // Duplicate code
      // ...

      cv::Mat integral_1st_order;
      cv::integral(input, integral_1st_order);

      input.forEach<double>(
        [&integral_1st_order, this](double& pixel, const int* position) {
          Process(integral_1st_order, pixel, position);
        });

      // Duplicate code
      // ...
    }

    void Process(const cv::Mat& integral_1st_order,
                 double& pixel,
                 const int* position) {
      // derived class must implement this
    }
  };

  template <>
  class IntegralImageCalculator<2> {
    void Iterate(cv::Mat& input) {
      // Duplicate code
      // ...

      cv::Mat integral_1st_order;
      cv::Mat integral_2nd_order;
      cv::integral(input, integral_1st_order, integral_2nd_order);

      input.forEach<double>(
        [&integral_1st_order, this](double& pixel, const int* position) {
          Process(integral_1st_order, integral_2nd_order, pixel, position);
        });

      // Duplicate code
      // ...
    }

    void Process(const cv::Mat& integral_1st_order,
                 const cv::Mat& integral_2nd_order,
                 double& pixel,
                 const int* position) {
      // derived class must implement this
    }
  };

如您所见,每个订单都有一个额外的求和矩阵。此外,派生类有很多重复代码和特定代码。我想知道是否有办法用 CRTP 解决它们。

【问题讨论】:

  • 为什么需要CRTPType模板参数?在您的示例中,未使用它。如果你真的需要它,为什么不通过BaseA&lt;Derived&gt;而不是BaseA
  • 一方面,你的编译器是对的; Derived&lt;size_t&gt; 不是您的模板的有效实例化。另一方面,您是否考虑过如何将IntegralImageCalculator&lt;1&gt; 定义为BaseB 的实例化作为基类? 1 如何与enable_crtp 通信? (在这种情况下,向前跳过可能是一个有用的技巧 - 只是不要忘记回顾您在某些时候跳过的内容。)
  • @Evg 我已经更新了代码,诀窍是摆脱菱形继承,您可以在这里查看更多内容fluentcpp.com/2017/05/19/crtp-helper
  • 我建议将钻石继承添加到您的问题中。
  • fluentcpp 链接没有任何意义。介绍性示例is broken。 CRTP 根本不是这样工作的。 template &lt;typename T&gt; struct NumericalFunctions : crtp&lt;T&gt; 与我们所知道和喜爱的 CRTP 无关。我建议不要关注那个页面。

标签: c++ templates crtp


【解决方案1】:

问题中缺少一些细节,但让我尝试为您提供一种可能的解决方案。即使它不是您所需要的,我希望它可以帮助您。

template<class T>
class Base {
public:
    void Iterate(cv::Mat& input) {
        std::array<cv::Mat, T::Order> integrals;

        std::apply([&input](auto&... integrals) { 
            cv::integral(input, integrals...); }, integrals);

        input.forEach<double>([&integrals, this](double& pixel, const int* position) {
            auto Process = [&](auto&... integrals) {
                static_cast<T*>(this)->Process(integrals..., pixel, position);
            };
            std::apply(Process, integrals);
        });
    }
};

template<std::size_t Order_, class Derived>
class IntegralImageCalculator : public Base<Derived> {
public:
    static constexpr std::size_t Order = Order_;
};

class A : public IntegralImageCalculator<1, A> {
public:
    void Process(const cv::Mat&, double& pixel, const int* position) {
        // implementation
    }
};

class B : public IntegralImageCalculator<2, B> {
public:
    void Process(const cv::Mat&, const cv::Mat&, double& pixel, const int* position) {
        // implementation
    }
};

Compilable example 带有用于 cv 的琐碎存根。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多