MPL-подобный вектор с вариадическими шаблонами: вставка - PullRequest
0 голосов
/ 06 марта 2012

Мне интересно, как можно написать Boost MPL -подобный vector_c с использованием шаблонов с переменными числами. Я уже написал следующий фрагмент кода:

template <std::size_t element, std::size_t ... E>
struct vector
{
    typedef vector<E ...> next;

    static constexpr std::size_t size()
    {
        return sizeof... (E);
    }

    static constexpr std::size_t value()
    {
        return element;
    }
};

template <std::size_t element>
struct vector<element>
{
    // no need to define 'next' here

    static constexpr std::size_t size()
    {
        return 1;
    }

    static constexpr std::size_t value()
    {
        return element;
    }
};

Вы можете заметить, что vector должен содержать хотя бы один элемент, но это не является для меня ограничением. С приведенными выше определениями очень легко написать «функции» для доступа к элементам для данного индекса:

template <std::size_t index, typename T>
struct get
{
    typedef typename get<index - 1, typename T::next>::type type;
};

template <typename T>
struct get<0, T>
{
    typedef T type;
};

Например, get<1, vector<1, 2, 3>> возвращает правильный результат 2. Теперь мой вопрос: Как реализовать функцию вставки? Причина, по которой я не использую MPL, заключается в том, что когда я пробовал его insert<>, он не возвращал vector_c. В частности, вставка должна применяться следующим образом:

insert<vector<1, 3, 4>, 1, 2>::type
//     ^                ^  ^
//     type            at  element

который должен дать vector<1, 2, 3, 4>. Это возможно?

Ответы [ 2 ]

2 голосов
/ 07 марта 2012

В пересчете на Haskell,

insert list 0 element = element : list
insert list at element = (head list) : insert (tail list) (at-1) element 

и перевод этого в шаблоны C ++:

// insert list at element =
template <typename List, size_t at, size_t element>
struct Insert
{
    typedef typename
        // insert (tail list) (at-1) element
        Insert<typename List::next, at-1, element>::type::
        // (head list) : …
        template push_front<List::value()>::type
    type;
};

// insert list 0 element = 
template <typename List, size_t element>
struct Insert<List, 0, element>
{
    // element : list
    typedef typename List::template push_front<element>::type type;
};

Обратите внимание, что вам нужно определить примитив push_front в обоих vector:

template <std::size_t element, std::size_t ... E>
struct vector<element, E...>
{
    template <size_t x>
    struct push_front
    {
        typedef vector<x, element, E...> type;
    };
};
1 голос
/ 07 марта 2012

Если вы хотите, чтобы MPL возвращал vector_c после вставки, вы должны объединить его в vector_c с помощью as_vector.

Здесь вы имеете дело с полуфункциональным языком, поэтому, если вы хотите вставить его, вам нужно перестроить новый vector_c из старого и индекса / позиции. Что делает MPL, поскольку такая реконструкция очень утомительна, так это возвращение типа, который действует как вектор (то есть следовать концепции статической последовательности) и имеет перегрузку get <>, которая знает, что, когда требуется позиция N, проверяет значения вставки, чтобы увидеть что вернуть.

...