Начиная с C ++ 17, можно написать if
блок, который будет выполняться точно так же, как это:
#include <iostream>
int main() {
for (unsigned i = 0; i < 10; ++i) {
if (static bool do_once = true; do_once) { // Enter only once
std::cout << "hello one-shot" << std::endl;
// Possibly much more code
do_once = false;
}
}
}
Я знаю, что мог бы обдумать это, и есть другие способы решить это, но все же - возможно ли написать это как-то так, так что do_once = false
в конце нет необходимости ?
if (DO_ONCE) {
// Do stuff
}
Я думаю, вспомогательная функция, do_once()
содержащая static bool do_once
, но что, если я хотел бы использовать эту же функцию в разных местах? Может ли это быть время и место для #define
? Надеюсь нет.
c++
if-statement
c++17
нада
источник
источник
if (i == 0)
? Это достаточно ясно.std::call_once
это вариант (он используется для многопоточности, но все еще делает свою работу).if
условиях, могут бытьstatic
. Это умно.Ответы:
Используйте
std::exchange
:Вы можете сделать его короче, изменив значение истины:
Но если вы часто этим пользуетесь, не думайте, а вместо этого создайте обертку:
И используйте это как:
Ссылка на переменную не должна быть вне условия, поэтому имя нам не очень дорого. Черпая вдохновение из других языков, таких как Python, которые придают
_
идентификатору особое значение , мы можем написать:Дальнейшие улучшения: воспользуйтесь разделом BSS (@Deduplicator), избегайте записи в память, когда мы уже запустили (@ShadowRanger), и дайте подсказку по прогнозированию ветвления, если вы собираетесь тестировать много раз (например, как в вопросе):
источник
#define ONLY_ONCE if (static bool DO_ONCE_ = true; std::exchange(DO_ONCE_, false))
использовать в качестве:ONLY_ONCE { foo(); }
_
используется во многих программах для обозначения переводимых строк. Ожидайте, что интересные вещи случатся._
для переменной было бы не Pythonic. Вы не используете_
переменные, на которые будут ссылаться позже, только для хранения значений, где вы должны предоставить переменную, но вам не нужно это значение. Обычно используется для распаковки, когда вам нужны только некоторые значения. (Существуют и другие варианты использования, но они довольно сильно отличаются от варианта одноразового значения.)Может быть, не самое элегантное решение, и вы не видите никакого фактического
if
, но стандартная библиотека фактически покрывает этот случай: смstd::call_once
.Преимущество здесь в том, что это потокобезопасно.
источник
call_once
меня означает, что ты хочешь позвонить однажды. Сумасшедший, я знаю.C ++ имеет встроенный примитив потока управления, который уже состоит из "( before-block; условие; after-block )":
Или хакер, но короче
Тем не менее, я думаю, что любой из методов, представленных здесь, следует использовать с осторожностью, поскольку они (пока?) Не очень распространены.
источник
b == false
:Thread 1
оценивает!b
и входит в цикл,Thread 2
оценивает!b
и входит в цикл,Thread 1
выполняет свою работу и покидает цикл for, устанавливаяb == false
в!b
ieb = true
...Thread 2
выполняет свои функции и покидает цикл for, устанавливаяb == true
в!b
ieb = false
, что позволяет всему процессу повторяться бесконечно)b=!b
, это выглядит хорошо, но вы на самом деле хотите, чтобы значение было ложным, поэтомуb=false
предпочтительнее.В C ++ 17 вы можете написать
во избежание поиграться с
i
в теле цикла.i
начинается с 0 (гарантированным стандартом), а выражение после;
множествi
в1
первый раз она вычисляется.Обратите внимание, что в C ++ 11 вы можете добиться того же с помощью лямбда-функции
что также имеет небольшое преимущество в том, что
i
не просачивается в тело петли.источник
static int i;
(я действительно не уверен) может быть одним из тех случаев, когдаi
гарантированно будет инициализироваться0
, здесь гораздо понятнее использоватьstatic int i = 0;
.Это решение является поточно-ориентированным (в отличие от многих других предложений).
источник
()
является необязательным (если он пуст) в лямбда-декларации?Вы можете заключить одноразовое действие в конструктор статического объекта, который вы создаете вместо условного.
Пример:
Или вы действительно можете придерживаться макроса, который может выглядеть примерно так:
источник
Как сказал @damon, вы можете избежать использования
std::exchange
, используя убывающее целое число, но вы должны помнить, что отрицательные значения переходят в истину. Способ использовать это будет:Перевод этого в необычную оболочку @ Acorn будет выглядеть так:
источник
Хотя использование,
std::exchange
как предлагает @Acorn, является, вероятно, самым идиоматическим способом, операция обмена не обязательно является дешевой. Хотя, конечно, статическая инициализация гарантированно является поточно-ориентированной (если вы не скажете компилятору не делать этого), поэтому любые соображения по поводу производительности в любом случае оказываются бесполезными в присутствииstatic
ключевого слова.Если вы обеспокоены микро-оптимизация (как люди , использующих C ++ часто), вы могли бы, а поцарапать
bool
и использоватьint
вместо этого, что позволит использовать постдекремент (или , вернее, приращение , поскольку в отличие отbool
декрементаint
будет не насыщать к нулю ...):Раньше у этого
bool
были операторы увеличения / уменьшения, но они давно устарели (C ++ 11 - не уверен?) И должны быть полностью удалены в C ++ 17. Тем не менее, вы можете уменьшитьint
просто отлично, и это, конечно, будет работать как логическое условие.Бонус: Вы можете реализовать
do_twice
илиdo_thrice
аналогичным образом ...источник
bool
и уменьшалась когда-то. Но инкремент прекрасно работает сint
. Посмотреть онлайн демо: coliru.stacked-crooked.com/a/ee83f677a9c0c85ado_once
оборачивается и в конечном итоге снова достигает 0 (и снова, и снова ...).Основываясь на великолепном ответе @ Вирсавии за это - просто сделал это еще проще.
В
C++ 17
, вы можете просто сделать:(В предыдущих версиях просто объявляли
int i
вне блока. Также работает в C :)).Простыми словами: вы объявляете i, который принимает значение по умолчанию, равное нулю (
0
). Ноль - ложь, поэтому мы используем!
оператор восклицательного знака ( ) для его отрицания. Затем мы принимаем во внимание свойство приращения<ID>++
оператора, который сначала обрабатывается (назначается и т. Д.), А затем увеличивается.Следовательно, в этом блоке я буду инициализироваться и иметь значение
0
только один раз, когда блок будет выполнен, а затем значение будет увеличиваться. Мы просто используем!
оператор, чтобы отрицать его.источник