а по моему, лесенка циклов читабельнее. Всё понятно — нужно буквально десять секунд, чтобы понять что происходит. Если же ввести что-то типа Variants, чужой человек зайдёт в файл variants.h и тут же застрелится.
Хотя конечно, если стоит задача поиграться с вариадиками...
Здравствуйте, koenjihyakkei, Вы писали:
K>Можно ли как-нибудь такое провернуть? K>Цель — избавиться от лесенки форов.
Есть ж ranges-v3 ( который кстати в C++20 будет ) https://github.com/ericniebler/range-v3
Рабочий пример:
#include"range/v3/view/cartesian_product.hpp"#include <iostream>
int main() {
const auto as = {32, 64};
const auto bs = {true, false};
const auto cs = {8, 16, 32, 64};
for (const auto v : ranges::view::cartesian_product(as, bs, cs)) {
auto[a, b, c] = v;
std::cout << a << " " << b << " " << c << '\n';
}
return 0;
}
Здравствуйте, LaptevVV, Вы писали:
K>>Цель — избавиться от лесенки форов. LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным. LVV>Представь себе число из n "цифр" LVV>Каждая "цифра" соответствует вложенному одному циклу. LVV>Значение "цифры" — это количество повторений этого вложенного цикла. LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот. LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл. LVV>Цифры числа, конечно могут быть в разных "системах счисления" LVV>Надеюсь, понятно объяснил.
Чорд, это самое короткое и понятное доказательство "P = NP" что я когда либо видел!
Здравствуйте, koenjihyakkei, Вы писали:
K>Проблема именно в идентации, но в отдельную функцию выносить не хочется, потому что там не работают gtest'овские ассерты.
Здравствуйте, koenjihyakkei, Вы писали: K>Можно ли как-нибудь такое провернуть? K>Цель — избавиться от лесенки форов.
Если для тестов, то может просто так писать:
for (auto a : { 32, 64} ) for (auto b : { true, false} ) for (auto c : { 8, 16, 32, 64 } )
{
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, koenjihyakkei, Вы писали:
K>Есть такой код (форов может быть гораздо больше): K> . . . K>Можно ли как-нибудь такое провернуть? K>Цель — избавиться от лесенки форов.
С такой задачкой и самому было бы интересно поиграться. Забалабесить что-нибудь типа, cartesian_product, cortesian_iterator, cortesian_range... Имея вариадики, можно сделать просто конфетку.
Здравствуйте, sergii.p, Вы писали:
SP>а по моему, лесенка циклов читабельнее. Всё понятно — нужно буквально десять секунд, чтобы понять что происходит. Если же ввести что-то типа Variants, чужой человек зайдёт в файл variants.h и тут же застрелится.
А это уже вопрос кривизны рук исполнителя. Ну зайдет он в "cartesian_product.hpp", увидит что то типа такого:
#pragma once
#include"cartesian_product_detail.hpp"template <typename...Ranges>
cartesian_product<Ranges...> make_cartesian_product(Ranges&&...);
Ну и где-нибудь, в этом же файле, или отдельно, в документации, небольшой пример, как этим пользоваться:
А больше ему ничего видеть и не нужно. И где здесь повод, чтобы стреляться? Это только в кривых руках, и при путанице в голове, сложность реализации автоматически означает сложность в использовании. Настоящие профессионалы же тем и отличаются, что умеют сложные вещи сделать простыми.
Здравствуйте, LaptevVV, Вы писали:
K>>Цель — избавиться от лесенки форов. LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным. LVV>Представь себе число из n "цифр" LVV>Каждая "цифра" соответствует вложенному одному циклу. LVV>Значение "цифры" — это количество повторений этого вложенного цикла. LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот. LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл. LVV>Цифры числа, конечно могут быть в разных "системах счисления" LVV>Надеюсь, понятно объяснил.
Здравствуйте, LaptevVV, Вы писали:
K>>Цель — избавиться от лесенки форов. LVV>Очень часто многократно вложенный цикл можно заменить двукратным вложенным. LVV>Представь себе число из n "цифр" LVV>Каждая "цифра" соответствует вложенному одному циклу. LVV>Значение "цифры" — это количество повторений этого вложенного цикла. LVV>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот. LVV>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл. LVV>Цифры числа, конечно могут быть в разных "системах счисления" LVV>Надеюсь, понятно объяснил.
В данном случае, думаю можно обойтись одним циклом.
for (auto a : { 32, 64} ) — перебирается 2 варианта, 0 — 32, 1 — 64
for (auto b : { true, false} ) — перебирается 2 варианта, 0 — false, 1 — true
for (auto c : { 8, 16, 32, 64 } ) — перебирается 4 варианта, т.е. хватит 2 бита — 00 — 8, 16 — 01, 32 — 10, 64 — 11
Пройдём в цикле for ( int i = 0; i < 16; i++ ) и переберём все варианты, но по сравнению c тремя циклами, по коду будет неочевидно, зачем нужен этот цикл и к тому,же нужно будет интерпретировать такое представление в исходный вид для дальнейшей обработки. Т.е. — к этому коду потребуется подробный комментарий, который будет больше, чем код.
K>Цель — избавиться от лесенки форов.
Очень часто многократно вложенный цикл можно заменить двукратным вложенным.
Представь себе число из n "цифр"
Каждая "цифра" соответствует вложенному одному циклу.
Значение "цифры" — это количество повторений этого вложенного цикла.
Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот.
А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл.
Цифры числа, конечно могут быть в разных "системах счисления"
Надеюсь, понятно объяснил.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
LVV>>Очень часто многократно вложенный цикл можно заменить двукратным вложенным. LVV>>Представь себе число из n "цифр" LVV>>Каждая "цифра" соответствует вложенному одному циклу. LVV>>Значение "цифры" — это количество повторений этого вложенного цикла. LVV>>Тогда внешний цикл — это перебор "цифр" числа. Либо от младшего "разряда" к старшему, либо наоборот. LVV>>А перебор значений каждой цифры от наименьшего до требуемого — это вложенный цикл. LVV>>Цифры числа, конечно могут быть в разных "системах счисления" LVV>>Надеюсь, понятно объяснил. MD>Чорд, это самое короткое и понятное доказательство "P = NP" что я когда либо видел!
Да при чем здесь доказательство-то?
Просто практика.
Ведь общее количество повторений не сокращается, просто код становится проще.
Ну, я подобный подход использовал при программировании числовых ребусов.
Но там все "цифры" в одной системе счисления, в 10-ной.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, rg45, Вы писали:
R>Вот здесь нашлось что-то похожее: https://codereview.stackexchange.com/questions/198475/generalized-cartesian-product.
R>С такой задачкой и самому было бы интересно поиграться. Забалабесить что-нибудь типа, cortesian_product, cortesian_iterator, cortesian_range... Имея вариадики, можно сделать просто конфетку.
Это используется в юнит тестах, где чужих не бывает Самая основная проблема в том, что идентация сильно съезжает вправо при большом количестве форов. В общем некрасиво и неудобно.
Эээх сначала так обрадовался, потому что код используется как раз в gtest. Но потом понял, что нужно писать отдельный Test fixture и вообще все сильно переделывать
Здравствуйте, koenjihyakkei, Вы писали:
K>Здравствуйте, sergii.p, Вы писали:
K>Это используется в юнит тестах, где чужих не бывает Самая основная проблема в том, что идентация сильно съезжает вправо при большом количестве форов. В общем некрасиво и неудобно.
Юнит тесты должны мыть максимально незамутнёнными и удобоотлаживаемыми.
Если проблема в идентации, я бы выносил внутренние функции, если проблема ещё и в дублировании этого набора циклов -- циклы вынести в метод, принимающий функтор.
Здравствуйте, Alexander G, Вы писали:
AG>Если проблема в идентации, я бы выносил внутренние функции, если проблема ещё и в дублировании этого набора циклов -- циклы вынести в метод, принимающий функтор.
Проблема именно в идентации, но в отдельную функцию выносить не хочется, потому что там не работают gtest'овские ассерты.
Здравствуйте, koenjihyakkei, Вы писали:
K>Проблема именно в идентации, но в отдельную функцию выносить не хочется, потому что там не работают gtest'овские ассерты.
TEST(FooTest, Bar) {
Subroutine();
// Aborts if Subroutine() had a fatal failure.if (HasFatalFailure()) return;
// The following won't be executed.
...
}
(Другая возможность — взять другой тестовый фреймворк, вроде Boost.Test, где fatal failures всегда сделаны не на return, а на исключениях)