Классы шаблонов с элементами шаблона, проверьте инстанцирование

У меня есть проект C++ (библиотека) о классах шаблонов (разные типы матриц с разными контейнерами для каждого типа и разными value_type для контейнеров - то же самое для векторов и т. д.).

У каждого класса шаблонов есть элементы шаблона, потому что

DenseRectangularMatrix<std::vector<long double>> //type-container-value_type

должен уметь (если это 5x5) умножать на

DenseSymmetricMatrix<std::array<float,15>> //(5x5) type-container-value_type

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

Есть мысли по этому поводу?


person Chameleon    schedule 07.03.2013    source источник
comment
Итак, ваша функция умножения написана, и вы хотите, чтобы все перестановки матриц скомпилировались. Это правильно?   -  person Drew Dormann    schedule 08.03.2013
comment
Звучит как работа для модульного теста для меня...   -  person Nathan Monteleone    schedule 08.03.2013


Ответы (1)


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

Итак, моя идея состоит в том, чтобы разложить ваши типы на более простые типы и использовать шаблоны для их создания.

enum {
    RECTANGULAR,
    SYMMETRIC,
} DimKind;

enum {
    DENSE,
    PARSE
} Density;

enum {
    STD_ARRAY,
    STD_VECTOR
} ContainerType;

enum {
    FLOAT,
    DOUBLE
} CoordType;

template <CoordType CT>
struct coord_def {
};

struct coord_def<FLOAT>{
    typedef float type;
};

struct coord_def<DOUBLE> {
    typedef double type;
};


template <ContainerType Cont, CoordType Coord, int Dimension>
struct container_def {
};

template <CoordType Coord, int Dim>
struct container_def<STD_ARRAY, Coord, Dim> {
    typedef std::array<Coord,Dim> type;
    static const int dim = Dim;
    // add any other helper function needed to build the test case for that particular
    // container
};

template <CoordType Coord, int Dim>
struct container_def<STD_VECTOR, Coord, Dim> {
    typedef std::vector<Coord> type;
    static const int dim = Dim;
};

template <Density D, DimKind DK, ContainerType Cont, 
                  CoordType Coord, int XDim, int YDim>
struct TestMatrix {
};

// here specialize the above according to the parameters
// you may need to include helper function to build an instance using the template
// parameters (dimension comesto mind)

Затем вы должны определить, какие виды операций вы хотите протестировать. Их, безусловно, можно разделить на категории «Матрица с компонентом», «Матрица с вектором», «Матрица с матрицей».

enum { 
    // matrix ops list
} MatrixOp;

template <MatrixOp Op, typename M1, typename M2, typename Ret>
Ret binary_op(M1 m1, M2 m2);

 // overload for specific functions

template <MatrixOp Op,
                  ContainerType Cont1, ContainerType Cont2
                   CoordType Coord1, CoordType Coord2,
                   int XDim1, int YDim1, int XDim2, int YDim2,
                   Denstity D1, Density D2,
                   DimKind K1, DimKind K2>
struct test_op {
    typedef TestMatrix<...>::type M1;
    typedef TestMatrix<...>::type M2;
    void test(M1 m1, M2 m2){
         binary_op<MatrixOp,M1,M2>(m1, m2);
     }
};

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

Например, параметр шаблона DenseSymmetricMatrix, кажется, указывает тип контейнера статического размера. Для такой матрицы n * n размер массива должен быть n * (n + 1) / 2. DenseRectangularMatrix с другой стороны, похоже, имеет свои размеры определяется во время выполнения. Но поскольку у вас есть отношение к измерениям, как указано выше, вы можете легко написать два тестовых примера в качестве шаблонов: один строит две матрицы с совпадающими размерами, а другой - с несовпадающими размерами.

Последний шаг — генерация всех возможностей. Простой сценарий, просматривающий все значения перечислений в раундах, должен помочь сгенерировать все возможные тесты.

Я уверен, что вы также можете использовать существующую среду модульного тестирования (например, boost) с этими шаблонами для создания своих тестов.

person didierc    schedule 08.03.2013