2016-06-22 2 views
3

У меня есть два кортежа, каждый из которых содержит контейнеры разных типов.Как сортировать два кортежа контейнеров?

std::tuple<containerA<typesA>...> tupleA; 
std::tuple<containerB<typesB>...> tupleB; 

Так, в качестве примера tupleA может быть определена следующим образом:

std::tuple<list<int>, list<float>> tupleA; 

двух контейнеров, containerA и containerB различные типы. typesA и typesB не пересекаются. Я хочу сортировать контейнеры внутри кортежей по их размерам и иметь доступ к ним по типу. Так, в качестве примера

std::tuple<list<int>, list<float>> tupleA {{2}, {3.3f, 4.2f}}; 
std::tuple<deque<double>, deque<uint8_t>> tupleB {{2.0, 1.2, 4.4}, {}}; 

auto sortedArray = sort(tupleA, tupleB); 
sortedArray == {deque<uint8_t>, list<int>, list<float>, deque<double>}; 
sortedArray.get<list<float>>() == {3.3f, 4.2f}; 
std::get<list<int>>(tupleA).push_back(4); 
std::get<list<int>>(tupleA).push_back(5); 
std::get<list<int>>(tupleA).push_back(6); 
sortedArray = sort(tupleA, tupleB); 
sortedArray == {deque<uint8_t>, list<float>, deque<double>, list<int>}; 

Наиболее важной частью является то, что я должен хранить sortedArray и размеры элементов в кортеже может измениться. Я не смог создать такую ​​функцию sort. Фактический синтаксис доступа к sortedArray не важен.

Я попытался использовать наивные индексы для данных контейнера внутри sortedArray, например, используя std::pair<A, 1>, чтобы ссылаться на второй элемент в кортеже A, однако я не могу получить доступ к информации кортежа через него, потому что это не constexpr

+0

Я не уверен, что это вполне возможно, так как кортеж типа, который должен быть известен во время компиляции, в то время как контейнеры внутри кортежа не constexpr контейнеров, и поэтому их элементы не будут известны до времени выполнения. – AndyG

+3

@ArchbishopOfBanterbury Вы не можете 'std :: sort' кортеж, потому что их порядок неизменен. Для этого будет создан новый тип. – user975989

+0

Ах, черт возьми, да, о чем я говорю, неважно. – ArchbishopOfBanterbury

ответ

1

Это возможно, но не легко.

Во-первых, вам необходимо сгенерировать список всех перестановок из N элементов (имеется N факториалов из них).

Запишите как время выполнения, так и объект подстановки времени компиляции (отдельный).

Составьте карту времени от перестановки до индекса. (шаг карты)

Преобразование вашего кортежа в вектор (индекс, размер). Сортировка по размеру. Извлеките перестановку. Сопоставьте это с индексом набора перестановок. (Шаг сортировки, использует шаг карты)

Напишите «волшебный переключатель», который принимает объект функции f и индекс перестановки и вызывает f с перестановкой времени компиляции. (волшебный шаг)

Напиши код, который переводит время компиляции и переупорядочивает кортеж на его основе. (шаг переупорядочения)

Напишите код, который принимает объект функции f и tuple. Сделайте (шаг сортировки). Сделайте (магический шаг), подав ему второй объект функции g, который берет переданный в перестановке и кортеж и (шаг переупорядочения), а затем вызывает f.

Вызвать функцию, которая делает это bob.

std::tuple<list<int>, list<float>> tupleA {{2}, {3.3f, 4.2f}}; 
std::tuple<deque<double>, deque<uint8_t>> tupleB {{2.0, 1.2, 4.4}, {}}; 

bob(concat_tuple_tie(tupleA, tupleB), [&](auto&& sorted_array){ 
    assert(std::is_same< 
    std::tuple<deque<uint8_t>&, list<int>&, list<float>&, deque<double>&>, 
    std::decay_t<decltype(sorted_array)> 
    >::value, "wrong order"); 
    sortedArray.get<list<float>>() == {3.3f, 4.2f}; 
}); 
std::get<list<int>>(tupleA).push_back(4); 
std::get<list<int>>(tupleA).push_back(5); 
std::get<list<int>>(tupleA).push_back(6); 
bob(concat_tuple_tie(tupleA, tupleB), [&](auto&& sorted_array){ 
    assert(std::is_same< 
    std::tuple<deque<uint8_t>&, list<float>&, deque<double>&, list<int>&>, 
    std::decay_t<decltype(sorted_array)> 
    >::value, "wrong order"); 
}); 

Лично я сомневаюсь, что вам нужно это сделать.

Я мог бы сделать это, но это может занять несколько часов, поэтому я не собираюсь делать это для ответа SO. Вы можете посмотреть мой код magic switch для большинства магии из вышеперечисленного. Другая сложная часть - это шаг перестановки.

Обратите внимание, что код использует стиль продолжения прохождения.Также обратите внимание, что каждые создается экземпляр lambda, включая неправильные, поэтому ваш код должен быть действительным для каждой перестановки. Это может привести к безумному количеству раздувания кода.

Альтернативное решение может включать создание оболочек для стирания типов вокруг ваших контейнеров и просто их сортировку, но это не то, о чем вы просили.

1

Проблемы вы описания звучит очень похоже вы хотите динамический полиморфизма, не статического полиморфизма — и ваши трудности в решении это потому, что вы застряли на попытку выразить с помощью инструментов для ведения статического полиморфизма.

т. Е. Вам нужен тип (иерархия) для коллекций (или указателей на коллекции), которые позволяют выбирать тип коллекции и тип данных во время выполнения, но при этом обеспечивают унифицированный интерфейс для нужных вам функций. size (например, путем наследования и виртуальных функций).

например. начало эскиза может выглядеть

struct SequencePointer 
{ 
    virtual size_t size() const = 0; 
    virtual boost::any operator[](size_t n) const = 0; 
}; 

template <typename Sequence> 
struct SLSequencePointer 
{ 
    const Sequence *ptr; 
    size_t size() const { return ptr->size(); } 
    boost::any operator[](size_t n) const { return (*ptr)[n]; } 
}; 
Смежные вопросы