#c #templates #crtp
Вопрос:
У меня есть следующий базовый класс CRTP:
template <typename T, template <typename> typename CRTPType>
struct enable_crtp {
auto underlying() -> Tamp; { return static_cast<Tamp;>(*this); }
auto underlying() const -> const Tamp; {
return static_cast<const Tamp;>(*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();
}
}
Для реальной проблемы у меня есть a IntegralImageCalculator
, который будет перебирать пиксели изображения, чтобы накопить сумму, основанную на его i-th order
:
template <size_t Order>
class IntegralImageCalculator;
template <>
class IntegralImageCalculator<1> {
void Iterate(cv::Matamp; input) {
// Duplicate code
// ...
cv::Mat integral_1st_order;
cv::integral(input, integral_1st_order);
input.forEach<double>(
[amp;integral_1st_order, this](doubleamp; pixel, const int* position) {
Process(integral_1st_order, pixel, position);
});
// Duplicate code
// ...
}
void Process(const cv::Matamp; integral_1st_order,
doubleamp; pixel,
const int* position) {
// derived class must implement this
}
};
template <>
class IntegralImageCalculator<2> {
void Iterate(cv::Matamp; 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>(
[amp;integral_1st_order, this](doubleamp; pixel, const int* position) {
Process(integral_1st_order, integral_2nd_order, pixel, position);
});
// Duplicate code
// ...
}
void Process(const cv::Matamp; integral_1st_order,
const cv::Matamp; integral_2nd_order,
doubleamp; pixel,
const int* position) {
// derived class must implement this
}
};
Как вы можете видеть, каждый заказ имеет дополнительную матрицу сумм. Кроме того, существует множество повторяющихся кодов и специальных кодов для производных классов. Интересно, есть ли способ решить их с помощью CRTP.
Комментарии:
1. Зачем вам нужен
CRTPType
параметр шаблона? В вашем примере он не используется. Если вам это действительно нужно, почему бы не пройтиBaseA<Derived>
вместоBaseA
этого ?2. С одной стороны, ваш компилятор прав;
Derived<size_t>
это недопустимый экземпляр вашего шаблона. С другой стороны, задумывались ли вы о том, как бы вы определилиIntegralImageCalculator<1>
с помощью экземпляраBaseB
как базовый класс? Как об этом1
сообщаетсяenable_crtp
? (Это один из тех случаев, когда пропуск вперед может оказаться полезным трюком-просто не забудьте оглянуться назад, на то, что вы пропустили в какой-то момент.)3. @Evg Я обновил код, хитрость в том, чтобы избавиться от алмазного наследования, вы можете увидеть больше здесь fluentcpp.com/2017/05/19/crtp-helper
4. Я предлагаю добавить алмазное наследование к вашему вопросу.
5. Ссылка на fluentcpp не имеет никакого смысла. Вводный пример нарушен . CRTP вообще так не работает.
template <typename T> struct NumericalFunctions : crtp<T>
не имеет ничего общего с CRTP, как мы знаем и любим. Я предлагаю не обращать внимания на эту страницу.
Ответ №1:
В вопросе отсутствуют некоторые детали, но позвольте мне попытаться дать вам одно возможное решение. Даже если это не совсем то, что вам нужно, я надеюсь, что это может вам помочь.
template<class T>
class Base {
public:
void Iterate(cv::Matamp; input) {
std::array<cv::Mat, T::Order> integrals;
std::apply([amp;input](autoamp;... integrals) {
cv::integral(input, integrals...); }, integrals);
input.forEach<double>([amp;integrals, this](doubleamp; pixel, const int* position) {
auto Process = [amp;](autoamp;... 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::Matamp;, doubleamp; pixel, const int* position) {
// implementation
}
};
class B : public IntegralImageCalculator<2, B> {
public:
void Process(const cv::Matamp;, const cv::Matamp;, doubleamp; pixel, const int* position) {
// implementation
}
};
Компилируемый пример с тривиальными заглушками для резюме.