只要数组 C++,就可以在一个语句中比较布尔变量

Compare Boolean Variables in one statement as long as array C++

假设我有一个布尔数组,其中有 5 个布尔变量都为真

bool boo[10];
for(int i = 0; i < 5; i++){
    boo[i] = true;
}

我希望将它们全部同时比较到一个 NAND 逻辑门中,因为我的问题是如果我总是比较两个变量并将合并的布尔值与 i+1 布尔变量进行比较。这给出了错误的结果。

    bool NANDGate(bool array[]){
    bool at;
    for(int i = 1; i < 5; i++){
        if(i == 1){
            at = !(array[i-1] && array[i]);
        }else{
            at = !(at && array[i]);
        }
    }
    return at;
}
// result here is true even though it should be false

当我将 boo 中的每个变量放入 NAND 门时,我想要的是一个正确的结果,所以可能看起来像这样:

bool func(bool array[]){
// some loop
result = !(array[0] && array[1] && array[2] && array[3] && array[4]);
return result;
}
// result here would be false

实际上它不必看起来像上面那样具有正确结果的解决方案。

编辑:这么多很棒的解决方案,谢谢大家

将您的定义替换为:

 bool NANDGate(bool array[]){
   bool at = array[0];
   for(int i = 1; i < 5; i++){
     at &&= array[i];
   }
   return !at;
 } 

非(!)必须放在最后才能兼容!(array[0] && array[1] && array[2] && array[3] && array[4]);

并且在您的定义中您还考虑了一些条目 2 次

但是把&&写到最后是没用的,最好只做:

 bool NANDGate(bool array[]){
   for(int i = 0; i < 5; i++){
     if (!array[i])
       return true;
   }
   return false;
 } 

下面应该这样做:

bool NANDGate(bool array[])
{
    for(int i = 0; i < 5; i++)
    {
        if (!array [i])
            return true;
    }
    return false;
}

如果您接受 C++17 解决方案,您可以使用辅助函数和模板折叠来实现所有 constexpr,如下所示

#include <iostream>
#include <utility>
#include <type_traits>

template <std::size_t N, std::size_t ... Is>
constexpr bool NANDhelper (bool const (&a)[N],
                           std::index_sequence<Is...> const &)
 { return ! (a[Is] && ...); }

template <std::size_t N>
constexpr bool NANDgate (bool const (&a)[N])
 { return NANDhelper(a, std::make_index_sequence<N>{}); }

int main ()
 {
   bool a[] { true, true, true, true, true };
   bool b[] { true, false, true, true, true };

   std::cout << NANDgate(a) << std::endl;
   std::cout << NANDgate(b) << std::endl;
 }

如果你不能使用C++17,但至少是C++14,你不能使用模板折叠,但你可以在一个未使用的数组初始化中模拟它;内容如下

template <std::size_t N, std::size_t ... Is>
constexpr bool NANDhelper (bool const (&a)[N],
                           std::index_sequence<Is...> const &)
 {
   using unused = bool[];

   bool val { true };

   (void)unused { true, (val &= a[Is])... };

   return ! val; 
 }

不幸的是,std::index_sequencestd::make_index_sequence 只能从 C++14 开始使用,所以,如果你想要类似的东西,你必须模仿它们(而 NANDhelper() 不能, 在 C++11 中,constexpr).

你也可以使用std::all_of,可读性好,如下:

DEMO

!std::all_of(std::begin(boo), std::begin(boo)+5, [](bool b){ return b; });

如果你想用这个STL函数定义函数bool NANDGate(...),那么下面的实现很适合你:

DEMO

bool NANDGate(const bool *arr, std::size_t n) 
{
    return !std::all_of(arr, arr+n, [](bool b){ return b; });
}

GCC 和 Clang 的性能

我通过 Quick C++ Benchmark[=74] 测试了上述函数(标记为 std::all_of)和 答案(标记为 Naive)的性能=] 在 C++14 和 O3 优化中同时使用 gcc-8.2 和 Clang-7.0。 结果如下。 水平线表示每个布尔数组的大小。 在两个编译器中,std::all_of 对于大于 ~8 的大小表现出比简单实现更好的性能:

海湾合作委员会(DEMO):

叮当声 (DEMO):

看看GCC的源码,这个结果的原因就很清楚了。 std::all_of 的当前 GCC 实现可以在 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. is called)

/// 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 提出的函数至少在这些编译器中也会表现出更好的性能。

另一种使用现代 C++ 的解决方案:

template <class CONTAINER>
bool NANDGate(const CONTAINER& container) {
    auto is_false = [](const auto& item) { return !(bool)item; };
    return std::any_of(std::begin(container), std::end(container), is_false);
}

因为这是C++,我们不需要写循环;我们可以使用 std::any_of 代替。

如果任何输入为假,我们需要我们的 NAND 门 return true

#include <algorithm>
#include <functional>

bool NANDGate(const bool array[])
{
    return std::any_of(array, array+5, std::logical_not<bool>());
}

int main()
{
    const bool boo[10] = { true, true, true, true, true };

    return NANDGate(boo);
}

C++ std::bitset 特别适用于这种情况。使用 C++11 的干净解决方案:

#include <bitset>
#include <iostream>


const unsigned gateSize = 5;


int main ()
{
    std::bitset<gateSize> booBits;

    //Set all bits to true by this simple function call...
    booBits.set();

    //... or some loop
    for (unsigned i = 0; i < gateSize; ++i)
        booBits[i] = 1;

    std::cout << !booBits.all() << std::endl; //This is your NANDgate
}

如果我使用 std::bitset 很多人会皱眉,但有了它就不需要函数了:

std::bitset<10> boo;
//...
bool boo_nand1= !boo.all();
bool boo_nan2=(~boo).any();