Шаблонни класове с членове на шаблона, проверете инстанцията

Имам C++ проект (библиотека) за шаблонни класове (различни типове матрици с различни контейнери за всеки тип и различен value_type за контейнери - същото за вектори и т.н.).

Всеки шаблонен клас има шаблонни членове, защото a

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 от друга страна изглежда има своите размери дефинирани по време на изпълнение. Но тъй като имате връзката на измеренията, както е изразено по-горе, можете лесно да напишете два тестови случая като шаблони: единият, който изгражда две матрици със съвпадащи размери, а другият с несъвпадащи размери.

Последната стъпка е генерирането на всички възможности. Един прост скрипт, преминаващ през всички стойности на enum на кръгове, трябва да помогне за генерирането на всички възможни тестове.

Сигурен съм, че можете също да използвате съществуваща рамка за модулен тест (като тази за повишаване) с тези шаблони, за да конструирате вашите тестове.

person didierc    schedule 08.03.2013