【发布时间】:2021-12-22 04:41:03
【问题描述】:
我有一个这样的数组[1, 0, 1, 1, 0, 0, ...]。
我怎样才能得到这个表达式的结果:1 XOR 0 XOR 1 XOR 1 XOR... without loop?
【问题讨论】:
我有一个这样的数组[1, 0, 1, 1, 0, 0, ...]。
我怎样才能得到这个表达式的结果:1 XOR 0 XOR 1 XOR 1 XOR... without loop?
【问题讨论】:
您可以创建一个函数模板,该模板接受一个数组并使用 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。
【讨论】:
成功了:
std::accumulate(arr.begin(), arr.end(), arr[0], std::bit_xor());
【讨论】:
arr[0],从而将其取消。尝试在 std::array<int, 1> arr = {1}; 上计算它,你会发现它错误地返回 0。如果 arr 是一个零大小的序列,它也会出现段错误。
在 C++14 中:
std::accumulate(arr.begin(),
arr.end(),
0,
std::bit_xor<void>())
【讨论】:
int)0 可能会调整为正确的类型。
0 替换为static_cast<decltype(*arr.begin())>(0)。但是 OP 的示例仅显示值为 0 和 1 的整数,在这种情况下这很好。
std::decay_t/std::remove_reference_t。