Когда-то уже заходила речь (кажется в G+), что хорошо было бы иметь в C++ функцию n_times для того, чтобы не нужно было циклы выписывать руками. Т.е. вместо того, чтобы писать:
const auto iterations = std::stoul(argv[1]); for( unsigned long i = 0; i != iterations; ++i ) do_some_action(); |
А можно было бы изобразить что-то вроде:
n_times( std::stoul(argv[1]), []{ do_some_action(); } ); |
Ну и в итоге дозрел до того, чтобы добавить n_times в нашу маленькую библиотечку cpp_util. Самый первый, черновой вариант, выглядит вот так:
template< typename COUNT_TYPE, typename LAMBDA > void n_times( COUNT_TYPE n, LAMBDA && body ) { loops_details::ensure_non_negative( n ); for( ; n; --n ) body(); } |
В нем вспомогательная функция ensure_non_negative в случае, если COUNT_TYPE является знаковым типом, проверит, чтобы n имел неотрицательное значение. В случае же отрицательного значения будет порождено исключение std::invalid_argument.
И вот тут у меня есть сомнения. Ведь такая проверка может вести к дополнительным накладным расходам. В каких-то случаях компилятор ее выбросит. Но в каких-то оставит. А это может не понравится некоторой части потенциальных пользователей. Посему есть мысль пойти по такому варианту:
using namespace cpp_util_3; // Пользователь не против получить исключение, если ошибся // со значением аргумента. n_times< checked_loop >( std::stol(argv[1]), []{ do_some_action(); } ); // Пользователь зуб дает, что все будет чики-пуки. n_times< unchecked_loop >( std::stol(argv[1]), []{ do_some_action(); } ); |
Или по такому:
using namespace cpp_util_3; // Пользователь не против получить исключение, если ошибся // со значением аргумента. n_times( untrusted_n(std::stol(argv[1])), []{ do_some_action(); } ); // Пользователь зуб дает, что все будет чики-пуки. n_times( trusted_n(std::stol(argv[1])), []{ do_some_action(); } ); |
Интересно мнение читателей: вам бы какой вариант был бы более удобен? Вообще без проверок? С проверками всегда? С отключаемыми проверками?
При этом если n -- это беззнаковое значение, то оно не проверяется вообще. Тут в дело вступает совсем простая шаблонная магия, которая устраняет избыточные проверки прям в compile-time.
PS. Кроме n_times еще хочется сделать up_to (или for_every_i):
using namespace cpp_util_3; for_every_i( 0, 10, [](auto i) { std::cout << i << std::endl; } ); |
Тут так же можно подумать на счет checked_loop/unchecked_loop...
Комментариев нет:
Отправить комментарий