2015-10-16 4 views
2
#include <string> 
#include <utility> 
#include <vector> 
#include <boost/hana.hpp> 
namespace hana = boost::hana; 

template <typename ...T> 
void indexed_T_work(T&& ...args) 
{ 
    auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>; 
    auto types = hana::make_tuple(std::forward<T>(args)...); 
    hana::for_each(
     hana::zip(indices, types) 
     , [](auto&& pair_) { /* Do index-dependent work with each `T` */ } 
     ); 
} 

int main() 
{ 
    indexed_T_work(5, 13, std::vector<std::string>{}, 32.f, 42, "foo"); 
} 

Я хотел бы использовать hana::zip на hana::tuple и hana::range_c, но hana::range_c не считается последовательность, что является необходимым условием для hana::zip. Каковы причины этого решения? Как я могу (идиоматически) выполнить мою задачу, соблюдая это решение?Почему `boost :: hana :: range_c` не последовательность?

ответ

5

Во-первых, существует несколько решений:

Solution 1

auto indices = hana::to<hana::tuple_tag>(hana::range_c<std::size_t, 0, sizeof...(T)>); 
auto types = hana::make_tuple(std::forward<T>(args)...); 
hana::for_each(hana::zip(indices, types), hana::fuse([](auto i, auto&& x) { 
    // ... 
})); 

Раствор 2

auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>; 
auto types = hana::make_tuple(std::forward<T>(args)...); 
hana::for_each(indices, [&](auto i) { 
    auto& x = types[i]; 
    // ... 
}); 

Раствор 3

auto types = hana::make_tuple(std::forward<T>(args)...); 
hana::size_c<sizeof...(T)>.times.with_index([&](auto i) { 
    auto& x = types[i]; 
    // ... 
}); 

Решение (1) имеет тот недостаток, что делает копию каждого args, потому что zip возвращает последовательность последовательностей, и все это Hana по значению. Поскольку это, вероятно, не то, что вы хотите, вы должны выбрать то, что вы предпочитаете между решениями (2) и (3), которые действительно эквивалентны.

Теперь, почему range s не моделирует концепцию Sequence, потому что это не имеет смысла. Концепция Sequence требует, чтобы мы могли создать произвольное Sequence с помощью функции hana::make. Следовательно, для любого Sequence тега S, hana::make<S>(...) необходимо создать Sequence тега S, который содержит .... Однако a range должен содержать смежный integral_constant s в некоторый интервал. Следовательно, если range был равен Sequence, hana::make<hana::range_tag>(...) должен содержать все, что ..., что разрушает инвариант range, если ... не смежны integral_constant с. Рассмотрим, например

hana::make<hana::range_tag>(hana::int_c<8>, hana::int_c<3>, 
          hana::int_c<5>, hana::int_c<10>) 

Это должно быть range, содержащий integral_constant s 8,3,5,10, который не имеет смысла. Другим аналогичным примером, показывающим, почему range не может быть Sequence, является алгоритм permutations. Алгоритм permutations принимает Sequence и возвращает Sequence из Sequence s, содержащий все перестановки. Ясно, что поскольку range может содержать только integral_constant с, нет смысла пытаться создать rangerange с. Таких примеров достаточно.

Иными словами, range s являются слишком специализированными, чтобы моделировать концепцию Sequence. Потенциал такой специализированной структуры заключается в том, что она очень эффективна для компиляции. Недостатком является то, что это не универсальный контейнер, и некоторые операции на нем не могут быть выполнены (например, zip). Тем не менее, вы можете полностью взять range и преобразовать его в полномасштабную последовательность, если знаете, что такое компромисс.