c++ - Могу ли я проверить небольшой массив bools за один раз?




arrays casting (4)

... И для обязательного ответа "накатить свой" мы можем предоставить простую "или" подобную функцию для любого массива bool[N] , например, так:

template<size_t N>
constexpr bool or_all(const bool (&bs)[N]) {
    for (bool b : bs) {
        if (b) { return b; }
    }

    return false;
}

Или более кратко,

template<size_t N>
constexpr bool or_all(const bool (&bs)[N]) {
    for (bool b : bs) { if (b) { return b; } }
    return false;
}

Это также имеет преимущество как короткого замыкания, как || и полностью оптимизирован, если рассчитывается во время компиляции.

Кроме того, если вы хотите исследовать первоначальную идею типа bool[N] для какого-либо другого типа, чтобы упростить наблюдение, я очень рекомендую вам не делать это, рассматривая его как char[N2] вместо этого, где N2 == (sizeof(bool) * N) . Это позволило бы вам обеспечить простую программу просмотра представления, которая может автоматически масштабироваться до фактического размера просматриваемого объекта, разрешать итерации по его отдельным байтам и более легко определять, соответствует ли представление определенным значениям (таким как, например, ноль или не -нуль). Я не совсем уверен, действительно ли такое исследование вызовет какой-либо UB, но я могу с уверенностью сказать, что конструкция любого такого типа не может быть жизнеспособным константным выражением из-за необходимости переинтерпретировать приведение к char* или unsigned char* или аналогичный (либо явно, либо в std::memcpy() ), и поэтому не может быть так просто оптимизирован.

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

bool boolArray[4];

И я хочу проверить, являются ли все элементы ложными, я могу проверить [0], [1], [2] и [3] по отдельности, или я могу пройти через это. Поскольку (насколько я знаю) значение false должно иметь значение 0, а все, кроме 0, - true, я подумал о простом выполнении:

if ( *(int*) boolArray) { }

Это работает, но я понимаю, что это полагается на то, что bool составляет один байт, а int - четыре байта. Если я приведу к (std :: uint32_t), все будет в порядке, или это все-таки плохая идея? У меня просто получилось 3 или 4 bools в массиве, и мне было интересно, если это безопасно, а если нет, то есть ли лучший способ сделать это.

Кроме того, в случае, если у меня более 4 бул, но менее 8, могу ли я сделать то же самое с std :: uint64_t или без знака long или что-то еще?


Вы можете использовать std::bitset<N>::any :

Any возвращает true если для любого из битов установлено значение true , в противном случае - false .

#include <iostream>      
#include <bitset>        

int main ()
{
  std::bitset<4> foo;
  // modify foo here


  if (foo.any())
    std::cout << foo << " has " << foo.count() << " bits set.\n";
  else
    std::cout << foo << " has no bits set.\n";

  return 0;
}

Live

Если вы хотите вернуть true если все или ни один из битов установлен на on, вы можете использовать std::bitset<N>::all или std::bitset<N>::none соответственно.


Несколько ответов уже объяснили хорошие альтернативы, особенно std::bitset и std::any_of() . Я пишу отдельно, чтобы указать, что, если вы не знаете что-то, чего не знаем мы, небезопасно вводить каламбур между bool и int таким образом по нескольким причинам:

  1. int может быть не четыре байта, как указано в нескольких ответах.
  2. ММ указывает в комментариях, что bool не может быть одним байтом. Я не знаю каких-либо реальных архитектур, в которых это когда-либо имело место, но, тем не менее, оно является специальным. Он (вероятно) не может быть меньше байта, если компилятор не выполняет очень сложную игру в прятки со своей моделью памяти, а многобайтовый тип bool кажется довольно бесполезным. Однако обратите внимание, что байт не должен быть 8 бит в первую очередь.
  3. int может иметь представление ловушек . То есть, для определенных битовых шаблонов допустимо вызывать неопределенное поведение, когда они приводятся к int . Это редко встречается на современных архитектурах, но может возникнуть (например) на ia64 или любой системе с подписанными нулями.
  4. Независимо от того, нужно ли вам беспокоиться о каком-либо из вышеперечисленного, ваш код нарушает строгое правило псевдонимов , поэтому компиляторы могут его «оптимизировать» в предположении, что bools и int являются полностью отдельными объектами с неперекрывающимися временами жизни. Например, компилятор может решить, что код, который инициализирует массив bool, является « мертвым хранилищем», и устранить его, потому что bool «должен был» перестать существовать * в какой-то момент до того, как вы разыменовали указатель. Также могут возникнуть более сложные ситуации, связанные с повторным использованием регистра и переупорядочением загрузки / сохранения. Все эти погрешности прямо разрешены стандартом C ++, который говорит, что поведение не определено, когда вы участвуете в этом типе наказания.

Вы должны использовать одно из альтернативных решений, предоставленных другими ответами.

* boolArray (с некоторыми оговорками, особенно в отношении выравнивания) повторно использовать память, на которую указывает boolArray путем приведения ее к int и сохранения целого числа, хотя, если вы действительно хотите это сделать, вы должны затем передать boolArray через std::launder если вы хотите прочитать полученный int позже. Независимо от этого, компилятор имеет право предполагать, что вы сделали это, когда увидит чтение, даже если вы не вызываете отмывание.






boolean