2016-02-16 3 views
4

Я пытаюсь создать вариационный контейнер-шаблон, в котором хранится набор векторов элементов. Точка этого контейнера - это элементы всех векторов, все связанные, и я хочу поддерживать эту корреляцию позже, но это не нужно для вычисления. Представьте, если хотите, vector_3 и ref_id какого-либо типа.Как я могу кормить кортежи?

Контейнер будет равномерно мутировать векторы вместе. Таким образом, части, которые я понимаю, выглядят так:

template<typename ...Elems> 
class container 
{ 
    std::tuple<std::vector<Elems>...> data_; 

public: 
    template<typename I> 
    const typename std::tuple_element<I, data_type>::type &nth_index() const 
    { return std::get<I>(data_); } 
}; 

Я борюсь со способом вставки. Я думал что-то вдоль линий:

void push_back(std::tuple<Elems...> &values) 
{ 
    std::tuple<std::back_insert_iterator<std::vector<Elems>>...> inserters; 
} 

Но я понятия не имею, как инициализировать этот «Inserters» кортеж. Я рассматривал различные примеры рекурсивных шаблонов здесь, в stackoverflow, и я не могу держать все это в своей голове достаточно долго, чтобы понять это.

Я предполагаю, если у меня был такой кортеж, я мог бы использовать простое задание:

inserters = values; 

Я хотел бы также написать аксессор во всех массивах, которая возвращает кортеж из значений:

std::tuple<Elems &...> operator[](const size_t index) 
{ 
    ... 
} 

Но еще раз, я не знаю, как инициализировать этот кортеж.

Я не могу быть единственным, кто когда-либо хотел это сделать, и я не могу найти хороший ресурс, чтобы его изучить. Тем временем я пытаюсь переварить оригинальное предложение шаблона шаблона для 0x. Проницательность была бы оценена. Я ограничен внедрением MSVC 2012.

ответ

1

C++ 11 раствор А с SFINAE и напечатайте черты:

template<typename ...Elems> 
class container { 
    std::tuple<std::vector<Elems>...> data_; 

    template<std::size_t N> 
    typename std::enable_if<(N <std::tuple_size<decltype(data_)>::value), int>::type 
    push_back_impl(std::tuple<Elems...> const &values) { 
    std::get<N>(data_).push_back(std::get<N>(values)); 
    return push_back_impl<N + 1>(values); 
    } 

    template<std::size_t N> 
    typename std::enable_if<(N == std::tuple_size<decltype(data_)>::value), int>::type 
    push_back_impl(std::tuple<Elems...> const &values) { 
    return 0; 
    } 

public: 

    void push_back(std::tuple<Elems...> const &values) { 
    push_back_impl<0>(values); 
    } 

}; 

Live Demo

, как для оператора индексного вам потребуется некоторое дополнительное оборудование найдено в это SO answer:

template <size_t ...I> 
struct index_sequence {}; 

template <size_t N, size_t ...I> 
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {}; 

template <size_t ...I> 
struct make_index_sequence<0, I...> : public index_sequence<I...> {}; 

template<typename ...Elems> 
class container { 
    std::tuple<std::vector<Elems>...> data_; 

    template<size_t ...I> 
    std::tuple<Elems&...> access_impl(std::size_t const idx, index_sequence<I...>) { 
    return std::tie(std::get<I>(data_)[idx]...); 
    } 

public: 

    std::tuple<Elems&...> operator[](std::size_t const idx) { 
    return access_impl(idx, make_index_sequence<sizeof...(Elems)>()); 
    } 
}; 

Live Demo

+0

Черная магия, друг мой. Я буду изучать это некоторое время, пытаясь понять все, что происходит. Это не интуитивно для меня. Есть ли у вас ресурс для изучения типовых и современных шаблонов? –

+0

@MatthewReddington Хорошее начало - это [Язык программирования C++ 4-го издания] (http://www.amazon.com/C-Programming-Language-4th/dp/0321563840/ref=sr_1_1?ie=UTF8&qid=1455664887&sr=8 -1 & ключевые слова = C% 2B% 2B).Но большинство вещей вы узнаете из SO и [cppreference] (http://en.cppreference.com/w/) и экспериментируете. – 101010

3
#include <vector> 
#include <tuple> 
#include <cstddef> 
#include <utility> 

template <typename... Elems> 
class container 
{ 
    using data_type = std::tuple<std::vector<Elems>...>; 

    data_type data_; 

public:  
    template <std::size_t I> 
    const typename std::tuple_element<I, data_type>::type& nth_index() const 
    { return std::get<I>(data_); } 

    void push_back(const std::tuple<Elems...>& values) 
    { 
     return push_back(std::make_index_sequence<sizeof...(Elems)>{}, values); 
    }  

    std::tuple<Elems&...> operator[](std::size_t index) 
    { 
     return get_elems(std::make_index_sequence<sizeof...(Elems)>{}, index); 
    } 

private: 
    template <std::size_t... Is> 
    void push_back(std::index_sequence<Is...>, const std::tuple<Elems...>& values) 
    { 
     using expand = int[]; 
     static_cast<void>(expand{ 0, (std::get<Is>(data_).push_back(std::get<Is>(values)), 0)... }); 
    } 

    template <std::size_t... Is> 
    std::tuple<Elems&...> get_elems(std::index_sequence<Is...>, std::size_t index) 
    { 
     return std::forward_as_tuple(std::get<Is>(data_)[index]...); 
    } 
}; 

DEMO

+0

MSVC 2012 не реализует зЬй :: integer_sequence (или constexpr), так что я вырвал его из N3658 с небольшими изменениями. –

+0

Кроме того, ваш трюк расширения раздул мне голову, но он не работает на моем компиляторе. Любые другие идеи? –

+0

@MatthewReddington try 'int expand [] = {0, (std :: get (данные _). Push_back (std :: get (значения)), 0) ...}; static_cast (развернуть); 'вместо –

Смежные вопросы