Как сделать так, чтобы специализация шаблона наследовалась от общей базы, не вызывая рекурсии? - PullRequest
0 голосов
/ 02 декабря 2018

Я пытаюсь реализовать матрицы в моей программе.Квадратные матрицы должны иметь дополнительные возможности, такие как вычисление определителя, но они также должны иметь все возможности матрицы.Я пытался сделать это таким образом - частично специализируя Матрицу и заставляя ее наследоваться от универсальной Матрицы.Я искал в Интернете, но я не нашел ничего подобного, только с типами, но он не работает с нетиповыми параметрами.

#include <iostream>

template <int a, int b>
class Matrix {
public:
    // some functions
    void g () {
        std::cout << "hi" << std::endl;
    }
};

template <int a>
class Matrix <a, a> : public Matrix <a,a> {
public:
    void f () {
        std::cout << "hello" << std::endl;
    }
};

int main () {
    Matrix <3,3> m;
    m.f();
   m.g();
}

Матрица на самом деле пытается унаследовать от себя, и яполучить ошибку

рекурсивный тип 'Matrix' undefined |агрегат 'Matrix <3, 3> m' имеет неполный тип и не может быть определен

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Этого можно добиться, разбив Matrix на два шаблона классов.

#include <iostream>

template <int a, int b>
class MatrixImpl {
public:
    // some functions
    void g () {
        std::cout << "hi" << std::endl;
    }
};

template <int a, int b>
class Matrix : public MatrixImpl <a, b> {};

template <int a>
class Matrix <a, a> : public MatrixImpl <a,a> {
public:
    void f () {
        std::cout << "hello" << std::endl;
    }
};

int main () {
    Matrix <3,3> m;
    m.f(); // ok
    m.g(); // ok

    Matrix <3,4> n;
    n.f(); // <- invalid
    n.g(); // ok
}
0 голосов
/ 02 декабря 2018

Вы не можете сделать это только с помощью шаблона класса.Второй класс шаблонов и некоторое метапрограммирование необходимы для выполнения чего-то вроде этого:

#include <iostream>

template <int a, int b>
class Matrix_impl {
public:
    // some functions
    void g () {
        std::cout << "hi" << std::endl;
    }
};

template <int a>
class special_matrix_impl : public Matrix_impl<a,a> {
public:
    void f () {
        std::cout << "hello" << std::endl;
    }
};

template<int a, int b>
struct which_template {

    typedef Matrix_impl<a, b> type;
};

template<int a>
struct which_template<a, a> {

    typedef special_matrix_impl<a> type;
};

template<int a, int b>
using Matrix=typename which_template<a, b>::type;

int main () {
    Matrix <3,3> m;
    m.f();
    m.g();
}

Реальные имена шаблонов здесь Matrix_impl и special_matrix_impl, а Matrix<a,b> выбирает подходящий.

В качестве альтернативы, единственный способ сделать это с одним шаблоном - это использовать дополнительный, по умолчанию, параметр шаблона для устранения неоднозначности специализации шаблона:

#include <iostream>

template <int a, int b, typename=void>
class Matrix {
public:
    // some functions
    void g () {
        std::cout << "hi" << std::endl;
    }
};

template <int a>
class Matrix <a, a, void> : public Matrix <a, a, int> {
public:
    void f () {
        std::cout << "hello" << std::endl;
    }
};

int main () {
    Matrix <3,3> m;
    m.f();
   m.g();
}

Довольно уродливо, но может оказатьсяуборщик в конце, если потребуется несколько специализаций.

...