Метавычесление констант в boost::mpl

282
09 мая 2017, 06:19

У меня есть задание на метавычисление констант с помощью boost::mpl:

Построить полумагический квадрат заданного размера по формуле:
1 + ((i - j + (n - 1) / 2) mod n) n + ((i + j + (n + 1) / 2) mod n).

С вычислением соответствующего числа, при известном i, j и n проблем не возникло:

template<int I, int J, int N>
struct MagicNumber
{
public:
    static const int value = 1 + ((I - J + (N - 1) / 2) % N) * N + ((I + J + 
(N + 1) / 2) % N);
};

И вот теперь возник вопрос: а как, с помощью mpl, при заданном n заполнить этими числами двумерный mpl::vector или какую-нибудь похожую структуру. В документации нашел mpl::push_back и mpl::for_each, но внятных примеров на их использование там не было.

Answer 1

Для начала, лучше использовать brigand для c++11 или boost::hana для с++14, это проще, удобнее и быстрее компилируется.

Если же вам нужен именно boost::mpl, то нужно делать примерно так:

#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/at.hpp>
template <class T>
struct check_type; // Для проверки значения типа во время компиляции
// Исходный заполнитель
template<int I, int J, int N>
struct magic_number_t
    : boost::mpl::int_<1 + ((I - J + (N - 1) / 2) % N) * N + ((I + J + (N + 1) / 2) % N)>
{ };
// Заполнитель строки (для строки известно I и N, переменная - J; I,J,N передаются как mpl::int_
template<class I, class N>
struct element_in_row_mfn{
    template<class J> 
    struct apply: magic_number_t<I::value, J::value, N::value> {};
};
// Генерирует I-ю строку, N - постоянная
template<std::size_t N>
struct make_row_mfn {
    template<class I> struct apply{
        typedef boost::mpl::range_c<int, 0 , N> col_range_;
        // результат метафункции
        typedef typename boost::mpl::transform<col_range_,       // Источник 0, 1, ...N-1
                         element_in_row_mfn<I, boost::mpl::int_<N> >, // Метафункция
                         boost::mpl::back_inserter<boost::mpl::vector<> > // Потребитель
                >::type type;
    };
};
enum {N = 3}; // input
// Применение метофункции make_columns<N> для каждого заголовка строки генерирует столбец
typedef typename boost::mpl::transform<
    boost::mpl::range_c <int, 0, N>,                 // Источник 0, 1, ...N-1
    make_row_mfn<N>,                                     // Метафункция
    boost::mpl::back_inserter<boost::mpl::vector<> > // Потребитель
>::type matrix; // Magic matrix
// это уже с++11
template <int i, class row>
using row_at = typename boost::mpl::at<row, boost::mpl::int_<i>>::type;
template <int i, int j, class Matrix>
using matrix_at = row_at<j, row_at<i, Matrix>>;
int main()
{
    // Вывод результата в виде сообщений об ошибке. Можно воспользоваться stsatic_assert вместо вывода
    check_type<matrix_at<0, 0, matrix > > v00;
    check_type<matrix_at<0, 1, matrix > > v01;
    check_type<matrix_at<0, 2, matrix > > v02;
    check_type<matrix_at<1, 0, matrix > > v10;
    check_type<matrix_at<1, 1, matrix > > v11;
    check_type<matrix_at<1, 2, matrix > > v12;
    check_type<matrix_at<2, 0, matrix > > v20;
    check_type<matrix_at<2, 1, matrix > > v21;
    check_type<matrix_at<2, 2, matrix > > v22;
    return 0;
}

Результат:

main.cpp: In function 'int main()':
main.cpp:55:43: error: aggregate 'check_type<mpl_::int_<6> > v00' has incomplete type and cannot be defined
     check_type<matrix_at<0, 0, matrix > > v00;
                                           ^~~
main.cpp:56:43: error: aggregate 'check_type<mpl_::int_<1> > v01' has incomplete type and cannot be defined
     check_type<matrix_at<0, 1, matrix > > v01;
                                           ^~~
main.cpp:57:43: error: aggregate 'check_type<mpl_::int_<-1> > v02' has incomplete type and cannot be defined
     check_type<matrix_at<0, 2, matrix > > v02;
                                           ^~~
main.cpp:59:43: error: aggregate 'check_type<mpl_::int_<7> > v10' has incomplete type and cannot be defined
     check_type<matrix_at<1, 0, matrix > > v10;
                                           ^~~
main.cpp:60:43: error: aggregate 'check_type<mpl_::int_<5> > v11' has incomplete type and cannot be defined
     check_type<matrix_at<1, 1, matrix > > v11;
                                           ^~~
main.cpp:61:43: error: aggregate 'check_type<mpl_::int_<3> > v12' has incomplete type and cannot be defined
     check_type<matrix_at<1, 2, matrix > > v12;
                                           ^~~
main.cpp:63:43: error: aggregate 'check_type<mpl_::int_<2> > v20' has incomplete type and cannot be defined
     check_type<matrix_at<2, 0, matrix > > v20;
                                           ^~~
main.cpp:64:43: error: aggregate 'check_type<mpl_::int_<9> > v21' has incomplete type and cannot be defined
     check_type<matrix_at<2, 1, matrix > > v21;
                                           ^~~
main.cpp:65:43: error: aggregate 'check_type<mpl_::int_<4> > v22' has incomplete type and cannot be defined
     check_type<matrix_at<2, 2, matrix > > v22;
READ ALSO
Как подключить Vreen в проект Qt?

Как подключить Vreen в проект Qt?

Как подключить Vreen в проект Qt? Пытался сделать все по инструкции, но ничего не вышлоТак как инструкция для ОС Linux (Ubuntu), а у меня Windows и стоит...

382
SFML+OpenGL: Как заставить работать вместе?

SFML+OpenGL: Как заставить работать вместе?

При использовании их вместе, то, что рисуется OpenGL не отображается

326
Как установить библиотеку Vreen в Qt?

Как установить библиотеку Vreen в Qt?

Как установить библиотеку Vreen в Qt? Официальная инструкция по установке для ОС Linux, а у меня стоит WindowsОчень прошу, кто может скинуть инструкцию...

259