【问题标题】:Is there any special C++ function to get XOR of all element of array?是否有任何特殊的 C++ 函数来获取数组所有元素的异或?
【发布时间】:2021-12-22 04:41:03
【问题描述】:

我有一个这样的数组[1, 0, 1, 1, 0, 0, ...]

我怎样才能得到这个表达式的结果:1 XOR 0 XOR 1 XOR 1 XOR... without loop?

【问题讨论】:

    标签: c++ algorithm


    【解决方案1】:

    您可以创建一个函数模板,该模板接受一个数组并使用 make_index_sequence 转发到一个辅助函数 - 然后使用折叠表达式来“解包”数组。

    这不需要任何循环,因为表达式将在编译时创建。

    #include <utility>
    
    namespace detail {
    template<class T, std::size_t... I>
    auto Xor_helper(const T& arr, std::index_sequence<I...>) {
        // make a fold expression of the whole array:
        return (... ^ arr[I]);      // arr[0] ^ arr[1] ^ ...
    }
    } // namespace detail
    
    template<class T, size_t N>
    auto Xor(const T(&arr)[N]) {
         return detail::Xor_helper(arr, std::make_index_sequence<N>{});
    }
    

    你可以像这样用你的数组来调用它:

    int main() {
        int arr[] = {0xf, 0x1, 0x3};
    
        std::cout << std::hex << Xor(arr) << '\n';
    }
    

    输出:

    d
    

    您可以查看这些模板@cppinsights 的结果。只需按下按钮,你就会看到上面的Xor(arr)变成return (arr[0UL] ^ arr[1UL]) ^ arr[2UL];


    上面的折叠表达式至少需要 C++17。适用于 C++98 及更高版本的解决方案可以改用递归。

    例子:

    namespace detail {
    
    template<std::size_t> struct index_tag{}; // one type per index used
    
    template<class T, size_t N, size_t I> // main function template
    T Xor_helper(const T(&arr)[N], index_tag<I>) {
        // recurse using `index_tag<I - 1>`:
        return Xor_helper(arr, index_tag<I - 1>()) ^ arr[I];
    }
    
    // Recursion stops when `index_tag<0>` is used:
    template<class T, size_t N>           // terminating case
    T Xor_helper(const T(&arr)[N], index_tag<0>) {
        return arr[0]; // no recursion, just return the value
    }
    } // namespace detail
    
    template<class T, size_t N>
    T Xor(const T(&arr)[N]) {
        // Call the helper using the index_tag for the last index in the array:
        return detail::Xor_helper(arr, detail::index_tag<N - 1>());
    }
    

    您还可以看到这些模板将如何被实例化@cppinsights

    【讨论】:

      【解决方案2】:

      成功了: std::accumulate(arr.begin(), arr.end(), arr[0], std::bit_xor());

      【讨论】:

      • 你应该接受@orlp 的回答而不是重复它。
      • @MattTimmermans,我已经在更新页面之前发布了我的解决方案并注意到他的回答,所以我没有看到它。
      • 我对你的答案投了反对票,不是因为我是第一个,而是因为你的答案不正确。它将在 XOR 计算中包含两次arr[0],从而将其取消。尝试在 std::array&lt;int, 1&gt; arr = {1}; 上计算它,你会发现它错误地返回 0。如果 arr 是一个零大小的序列,它也会出现段错误。
      • 是的,这是错误的。您应该从 0 而不是 arr[0] 开始累积。 @orlp 的答案是正确的
      【解决方案3】:

      在 C++14 中:

      std::accumulate(arr.begin(),
                      arr.end(),
                      0,
                      std::bit_xor<void>())
      

      【讨论】:

      • OP 没有说明数组的类型,所以 (int)0 可能会调整为正确的类型。
      • 是的,为了完全正确和通用,我们需要将0 替换为static_cast&lt;decltype(*arr.begin())&gt;(0)。但是 OP 的示例仅显示值为 0 和 1 的整数,在这种情况下这很好。
      • 我认为在这种情况下需要std::decay_t/std::remove_reference_t
      • @Jarod42 很可能,我已经有一段时间没有编写完全通用的 C++ 代码了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 2014-04-26
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      相关资源
      最近更新 更多