Вы также можете использовать std::all_of
с хорошей читабельностью следующим образом:
DEMO
!std::all_of(std::begin(boo), std::begin(boo)+5, [](bool b){ return b; });
Если вы хотите определить функцию bool NANDGate(...)
с помощью этой функции STL, тогда вам пригодится следующая реализация:
DEMO
bool NANDGate(const bool *arr, std::size_t n)
{
return !std::all_of(arr, arr+n, [](bool b){ return b; });
}
Производительность на GCC и Clang
Я проверил производительность вышеуказанной функции (с меткой std::all_of
) и принятый ответ (с меткой Naive
) с помощью Quick C ++ Benchmark с обоими gcc-8.2 и Clang-7.0 в C ++ 14 и O3 оптимизация.
Результат выглядит следующим образом.
Горизонтальная линия представляет размеры каждого логического массива.
В обоих компиляторах std::all_of
показывает лучшую производительность, чем наивная реализация для размеров, превышающих ~ 8:
GCC ( DEMO ):
Clang ( DEMO ):
Глядя на исходный код GCC, причина этого результата будет довольно ясна.
Текущую реализацию GCC std::all_of
можно увидеть в gcc / libstdc ++ - v3 / include / bits / stl_algo.h и следующей:
template<typename _InputIterator, typename _Predicate>
inline bool
all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred)
{
return __last == std::find_if_not(__first, __last, __pred);
}
, где std::find_if_not
также реализован в том же файле с помощью функции __find_if
.
Обратите внимание, что есть две перегрузки __find_if
.
Первый - очень простой, следующий:
template<typename _InputIterator, typename _Predicate>
inline _InputIterator
__find_if(_InputIterator __first, _InputIterator __last,
_Predicate __pred, input_iterator_tag)
{
while (__first != __last && !__pred(__first))
++__first;
return __first;
}
OTOH, вторая функция перегрузки для итераторов произвольного доступа и оптимизированная для них.
Реализация заключается в следующем.
Поскольку расстояние между итераторами произвольного доступа быстро вычисляется с постоянной сложностью O (1), это ручное развертывание цикла эффективно работает.
В нашем текущем случае boo
является необработанным указателем, который является итератором произвольного доступа.
Таким образом, эта оптимизированная функция перегрузки вызывается.
Это должно быть причиной того, что std::all_of
показывает лучшую производительность, чем наивная реализация для почти всех размеров:
DEMO (RAI ver. Называется)
/// This is an overload used by find algos for the RAI case.
template<typename _RandomAccessIterator, typename _Predicate>
_RandomAccessIterator
__find_if(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Predicate __pred, random_access_iterator_tag)
{
typename iterator_traits<_RandomAccessIterator>::difference_type __trip_count = (__last - __first) >> 2;
for (; __trip_count > 0; --__trip_count)
{
if (__pred(__first))
return __first;
++__first;
if (__pred(__first))
return __first;
++__first;
if (__pred(__first))
return __first;
++__first;
if (__pred(__first))
return __first;
++__first;
}
switch (__last - __first)
{
case 3:
if (__pred(__first))
return __first;
++__first;
case 2:
if (__pred(__first))
return __first;
++__first;
case 1:
if (__pred(__first))
return __first;
++__first;
case 0:
default:
return __last;
}
}
Хотя я не знаю подробностей реализации Clang, похоже, это также оптимизировано из приведенного выше графика.
Кроме того, по той же причине функции, предложенные @ 0x0x5453 и @TobySpeight, также будут показывать лучшую производительность, по крайней мере, в этих компиляторах.