Частичная специализация шаблоном класса C++
Появилась достаточно неоднозначная задача. Есть абстрактный модуль "Фильтр":
template <typename T, typename DelayLineType>
class FilterAbstract
{
public:
explicit FilterAbstract(uint32_t length);
explicit FilterAbstract(const FilterAbstract &object);
FilterAbstract &operator=(const FilterAbstract &object);
virtual ~FilterAbstract() = default;
virtual T Step(const T &value) = 0;
DelayLineType DelayLine;
Vector<T> Coefficients;
};
Далее я наследую абстрактный класс с частичной специализацией:
template <typename T>
class FilterOnCircularVectors : public FilterAbstract<T, CircularVector<T>>
{
public:
explicit FilterOnCircularVectors(uint32_t length);
explicit FilterOnCircularVectors(const FilterAbstract<T, CircularVector<T>> &object);
T Step(const T &value) override;
};
Теперь я помимо такого наследования хочу обеспечить частичную специализацию путем использования класса Complex<T> и тут появляется недопонимание как это реализовать правильно с одним и тем же именем в том же файле:
template <template T>
class FilterOnCircularVectors : public FilterAbstract<T, CircularVector<Complex<T>>>
{
public:
explicit FilterOnCircularVectors(uint32_t length);
explicit FilterOnCircularVectors(const FilterAbstract<T, CircularVector<Complex<T>>> &object);
Complex<T> Step(const Complex<T> &value) override;
};
Есть какие-то мысли на этот счет? Плодить классы с пометкой Complex не очень хочется.
UPD:
В VS2019 если создать два класса с такими именами и таким наследованием, то возникает ошибка из-за множественного определения.
Дело в том, что разное поведение должно быть у функции Step при CircularVector<T> и CircularVector<Complex<T>>
Ответы (3 шт):
В последнем примере вы изменяете возвращаемый и принимаемый тип. В базовом классе у вас инстанцируется
virtual T Step(const T &value) = 0;
А вы хотите
virtual Complex<T> Step(const Complex<T> &value) = 0;
Для того, чтобы было последнее вы должны подавать первым аргументом в шаблон не T, а Complex<T>, тогда всё должно работать
template <typename T>
class FilterOnCircularVectors : public FilterAbstract<Complex<T>, CircularVector<Complex<T>>>
{
public:
explicit FilterOnCircularVectors(uint32_t length);
explicit FilterOnCircularVectors(const FilterAbstract<Complex<T>, CircularVector<Complex<T>>> &object);
Complex<T> Step(const Complex<T> &value) override;
};
Заранее предупреждаю, что в данном случае вы не сможете воспользоваться полиморфизмом при подаче разных типов.
Если же вы хотите именно частичную специализацию, то нужно сделать так
template <typename T, typename DelayLineType>
class FilterAbstract<Complex<T>, DelayLineType>
{
public:
explicit FilterAbstract(uint32_t length);
explicit FilterAbstract(const FilterAbstract &object);
FilterAbstract &operator=(const FilterAbstract &object);
virtual ~FilterAbstract() = default;
virtual Complex<T> Step(const Complex<T> &value) = 0;
DelayLineType DelayLine;
Vector<T> Coefficients;
};
Тут нужно отделять шаблон от специализации. Если даже специализация частичная, то должна определяться именно эта специализация, а вы тот же шаблон пытаетесь переопределять. А нужно определять FilterOnCircularVectors< Complex<T> >, следующим образом:
template <typename T>
class FilterOnCircularVectors<Complex<T>>
: public FilterAbstract<T, CircularVector<Complex<T>>>
{
public:
/*Если классу нужны свои конструкторы, то нужно
в списке инициализации конструктора инициализировать
и базовый объект(он кажется даже не конструируется по
умолчанию)*/
Complex<T> Step(const Complex<T>& value) override;
};
Как заметил @AR Hovsepyan задача решается, но дополнительно необходимо соблюсти правила наследования абстрактной функции. Тогда решение будет выглядеть следующим образом:
template <typename T>
class FilterOnCircularVectors<Complex<T>>
: public FilterAbstract<T, CircularVector<Complex<T>>>
{
public:
/*Если классу нужны свои конструкторы, то нужно
в списке инициализации конструктора инициализировать
и базовый объект(он кажется даже не конструируется по
умолчанию)*/
explicit FilterOnCircularVectors<Complex<T>>(uint32_t length);
explicit FilterOnCircularVectors<Complex<T>>(const FilterAbstract<T, CircularVector<Complex<T>>> &object);
Complex<T> Step(const Complex<T> &value);
private:
T Step(const T &value) override;
};
Это связано с тем, что абстрактная функция наследуется с параметром T а для решения моей задачи требуется Complex<T>