Использование CRTP для создания собственной матрицы - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть иерархия классов, которые содержат некоторые собственные матрицы в качестве членов, но их размер зависит от производного класса.Я хочу иметь возможность объявлять матрицы в базовом классе, но иметь размер, используемый в производном классе.Я думал, что мог бы использовать CRTP для этого, но я не уверен, что я использую его правильно.Вот код, который я пробовал

template<typename T>
class Base {
public:
    const int matSize = static_cast(T*)(this)->_matSize;
    Eigen::Matrix<int, matSize, mastSize> Mat = Eigen::Matrix<int, matSize, matSize>::Zero();

    virtual void print() { std::cout << Mat << std::endl; };
};

class Derived1 : public Base<Derived1>{
public:
    const int _matSize = 3;
};

class Derived2 : public Base<Derived2>{
public:
    const int _matSize = 4;
};

int main(){
    Derived1 d1;
    d1.print();   // print a 3x3 zero matrix

    Derived2 d2;
    d2.print();   // print a 4x4 zero matrix

    std::cin.get();
    return 0;
}

Однако это не работает.Есть ли способ добиться чего-то подобного?

Редактировать:

Основная причина для выполнения вышеупомянутого состоит в том, что у меня есть функции, которые выполняют некоторую матричную алгебру, которая будет работать независимо от размера.Поэтому я хотел бы иметь возможность вызывать эту функцию для объектов различных производных классов и просто иметь возможность использовать одну и ту же функцию вместо того, чтобы иметь отдельные функции для каждого размера матрицы.

Кроме того, чтобы иметь интерфейс, который любойОбъект типа Base будет иметь матрицу Mat, размер которой будет зависеть от того, из какого производного класса Base он был создан.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Вы не можете получить доступ к членам Derived1 (из любого места за пределами Derived1), пока оно не будет полностью определено.Обычный обходной путь для этой проблемы заключается в использовании некоторого класса черт:

template<class D>
struct MyTraits;

template<typename T>
class Base {
public:
    static const int matSize = MyTraits<T>::_matSize;
    Eigen::Matrix<int, matSize, matSize> Mat = Eigen::Matrix<int, matSize, matSize>::Zero();

    virtual void print() { std::cout << Mat << std::endl; };
};

class Derived1;
template<>
struct MyTraits<Derived1> {static const int _matSize = 3;};

class Derived1 : public Base<Derived1>{
public:
};

Godbolt: https://godbolt.org/z/pf-B_R

Особенно, если Derived1 сам является шаблоном класса, черты будутбыть (частично) шаблонным, а также.Имеет ли это смысл в вашем случае, трудно определить из предоставленного вами кода.

Кстати: не нужно создавать Base::print() virtual.Суть статического полиморфизма заключается в том, чтобы избежать динамического полиморфизма.

0 голосов
/ 03 февраля 2019

Как я сказал в своем комментарии, на самом деле нет причин использовать CRTP только для того, что вы указали, но если вы настроены на этот шаблон по какой-то другой причине, должно сработать что-то вроде следующего (у меня нет Eigen::Matrix доступно, поэтому я заглушил необходимый интерфейс для компилятора):

#include <iostream>

namespace Eigen {
    template<typename T, int W, int H>
    class Matrix {
    public:
        static Matrix<T,W,H> Zero() {
            return Matrix<T, W, H>{};
        }

        std::ostream &print_on(std::ostream &strm) const {
            return strm;
        }
    };
}

template <typename T, int W, int H>
std::ostream &operator<<(std::ostream &strm, Eigen::Matrix<T,W,H> const &matrix) {
    return matrix.print_on(strm);
}

template<typename T, int S>
class Base {
public:
    Eigen::Matrix<int, S, S> Mat = Eigen::Matrix<int, S, S>::Zero();

    virtual void print() { std::cout << Mat << std::endl; };
};

class Derived1 : public Base<Derived1,3>{
public:
};

class Derived2 : public Base<Derived2,4>{
public:
};

template <int Size>
class AdvertisingDerived : public Base<AdvertisingDerived<Size>,Size> {
public:
    constexpr static int matrixSize = Size;
};

int main(){
    Derived1 d1;
    d1.print();   // print a 3x3 zero matrix

    Derived2 d2;
    d2.print();   // print a 4x4 zero matrix

    AdvertisingDerived<3> ad1;

    AdvertisingDerived<4> ad2;

    std::cin.get();
    return 0;
}
...