如何用更简洁方式静态断言一个std::array是另一个的子集?
静态判断constexpr std::array是否为子集的简洁实现
我有两个constexpr std::array:
constexpr std::array full = { 1,2,3 }; constexpr std::array subset = { 3 };
需要用静态断言判断第二个数组是否是第一个的子集——上面的例子断言应该成功,而下面的例子断言应该失败:
constexpr std::array full = { 1,2,3 }; constexpr std::array subset = { 3, 4 };
我已经写了一个可用的constexpr函数:
constexpr bool isSubset(decltype(full)& a, decltype(subset)& b) { for (const auto& subsetElement : b) { bool found = false; for (const auto& fullElement : a) { if (subsetElement == fullElement) { found = true; break; } } if (!found) { return false; } } return true; }
但想知道在最新C++标准下有没有更简洁的实现方式,比如不用decltype,甚至不用constexpr函数。
方法1:C++20范围库简化通用constexpr函数
可以将函数改成通用模板,摆脱对具体数组类型的依赖,同时用std::ranges::any_of简化内层循环逻辑:
#include <array> #include <ranges> template<typename T, std::size_t N, std::size_t M> constexpr bool isSubset(const std::array<T, N>& full, const std::array<T, M>& subset) { return std::ranges::all_of(subset, [&full](const auto& elem) { return std::ranges::any_of(full, [&elem](const auto& full_elem) { return elem == full_elem; }); }); } // 使用示例 constexpr std::array full = {1,2,3}; constexpr std::array subset = {3}; static_assert(isSubset(full, subset)); // 断言成功 constexpr std::array bad_subset = {3,4}; static_assert(!isSubset(full, bad_subset)); // 断言成功
这个版本通用性更强,无需decltype,借助C++20范围算法让代码更简洁,同时保留编译期计算能力。
方法2:C++20 constexpr lambda直接嵌入静态断言
如果不想单独定义函数,可直接在static_assert中使用constexpr lambda完成判断逻辑,代码更紧凑:
#include <array> #include <ranges> constexpr std::array full = {1,2,3}; constexpr std::array subset = {3}; static_assert([&]() constexpr { return std::ranges::all_of(subset, [&](const auto& elem) { return std::ranges::any_of(full, [&](const auto& fe) { return elem == fe; }); }); }()); // 断言成功 constexpr std::array bad_subset = {3,4}; static_assert(![&]() constexpr { return std::ranges::all_of(bad_subset, [&](const auto& elem) { return std::ranges::any_of(full, [&](const auto& fe) { return elem == fe; }); }); }()); // 断言成功
方法3:C++23 std::ranges::contains进一步简化
C++23新增的std::ranges::contains可以替代内层的any_of,让代码可读性更高、逻辑更直白:
#include <array> #include <ranges> template<typename T, std::size_t N, std::size_t M> constexpr bool isSubset(const std::array<T, N>& full, const std::array<T, M>& subset) { return std::ranges::all_of(subset, [&full](const auto& elem) { return std::ranges::contains(full, elem); }); } // 或者直接在断言中使用 constexpr std::array full = {1,2,3}; constexpr std::array subset = {3}; static_assert(std::ranges::all_of(subset, [&](const auto& elem) { return std::ranges::contains(full, elem); }));
内容的提问来源于stack exchange,提问作者AK87
相关产品推荐
相关产品推荐

