2012-03-06 1 views
0

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

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

С точки зрения 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; 
    }; 
}; 
+0

приятное решение - это помогает понять, как много повысить MPL можно было переписать/заменить вариативными шаблонами. – mark

+0

Тем временем я также пришел к выводу, что мне нужно написать функцию «push_front», однако я не понимал, что это должно быть внутри самого вектора! Я думаю, что невозможно написать push_front вне векторного класса, не так ли? – cschwan

+1

@cschwan: Конечно, вы можете * (пример: http://ideone.com/3F4UQ). Я просто не хочу этого делать. – kennytm

1

Если вы хотите, чтобы MPL возвратил vector_c после вставки, вы должны covnert его в vector_c usign as_vector.

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

+0

Спасибо за объяснение - где я могу найти 'as_vector'? – cschwan