初学者如何使用标准::any_of?

How to use std::any_of for a beginner?

本文关键字:of any 初学者 何使用 标准      更新时间:2023-10-16

我想将一个值与其他几个值进行比较,并检查它是否至少与其中一个值匹配,我认为它会像

if (x = any_of(1, 2 ,3)
// do something

但我在网上看到的例子是

bool any_of(InputIt first, InputIt last, UnaryPredicate)

那是什么意思?

C ++的新手,所以如果这是一个愚蠢的问题,请道歉。

有很多关于"C++迭代器">主题的文献和视频教程,你应该朝这个方向做一些研究,因为它是C++的基本概念。

关于这个问题的快速总结:迭代器是指向值集合(或范围(中的元素的东西。此类集合的几个示例:

  • std::vector是最常见的一种。它基本上是一个可调整大小的数组。
  • std::list是一个链表。
  • std::array是一个固定大小的数组,在C样式数组周围有一些很好的助手
  • int myInt[12]是一个 C 样式的整数数组。这个不应该再用了。

C++标准库中对值集合(如std::any_of(进行操作的算法通过两个迭代器获取集合。第一个迭代器InputIt first指向所述集合的开头,而InputIt last指向集合的末尾(实际上是结束之后的一个(。

UnaryPredicate是一个接受 1 个参数(一元(并返回布尔值(谓词(的函数。

为了让std::any_of做你想做的事,你必须把你的值放在一个集合中,xUnaryPredicate

int x = 3;
std::vector values = {1, 2, 3};
if (std::any_of(values.begin(), values.end(), [x](int y) { return x == y; }))
// ...

本例中的UnaryPredicate是 lambda 函数。

如您所见,根据您的示例,这是非常冗长的代码。但是,一旦你有一个想要比较的动态值堆积,或者你想检查比相等更复杂的事情,这个算法就会变得更加有益。

有趣的小实验

只是为了好玩,我做了一个小的代码片段来实现你想要的any_of。这是相当多的代码和相当复杂的(绝对不是初学者水平!(,但它非常灵活,实际上很好用。完整的代码可以在这里找到。

以下是您将如何使用它:

int main()
{
int x = 7;
std::vector dynamic_int_range = {1, 2, 3, 4, 5, 6, 7, 8};
if (x == any_of(1, 2, 3, 4, 5))
{
std::cout << "x is in the compile time collection!n";
}
else if (x == any_of(dynamic_int_range))
{
std::cout << "x is in the run time collection!n";
}
else
{
std::cout << "x is not in the collection :(n";
}   

std::string s = "abc";
std::vector<std::string> dynamic_string_range = {"xyz", "uvw", "rst", "opq"};
if (s == any_of("abc", "def", "ghi"))
{
std::cout << "s is in the compile time collection!n";
}
else if (s == any_of(dynamic_string_range))
{
std::cout << "s is in the run time collection!n";
}
else
{
std::cout << "s is not in the collection :(n";
}    
}

以下是它的实现方式:

namespace detail
{
template <typename ...Args>
struct ct_any_of_helper
{
std::tuple<Args...> values;
constexpr ct_any_of_helper(Args... values) : values(std::move(values)...) { }
template <typename T>
[[nodiscard]] friend constexpr bool operator==(T lhs, ct_any_of_helper const& rhs) noexcept
{        
return std::apply([&](auto... vals) { return ((lhs == vals) || ...); }, rhs.values);
}
};
template <typename Container>
struct rt_any_of_helper
{
Container const& values;
constexpr rt_any_of_helper(Container const& values) : values(values) { }
template <typename T>
[[nodiscard]] friend constexpr bool operator==(T&& lhs, rt_any_of_helper&& rhs) noexcept
{
return std::any_of(cbegin(rhs.values), cend(rhs.values), [&](auto val)
{
return lhs == val;
});
}
};
template <typename T>
auto is_container(int) -> decltype(cbegin(std::declval<T>()) == cend(std::declval<T>()), std::true_type{});
template <typename T>
std::false_type is_container(...);
template <typename T>
constexpr bool is_container_v = decltype(is_container<T>(0))::value;
}
template <typename ...Args>
[[nodiscard]] constexpr auto any_of(Args&&... values)
{
using namespace detail;
if constexpr (sizeof...(Args) == 1 && is_container_v<std::tuple_element_t<0, std::tuple<Args...>>>)
return rt_any_of_helper(std::forward<Args>(values)...);
else
return ct_any_of_helper(std::forward<Args>(values)...);
}

如果专家看到这段代码并想抱怨悬而未决的引用:来吧,谁会写这样的东西:

auto a = any_of(std::array {1, 2, 3, 4});
if (x == std::move(a)) // ...

这不是这个函数的用途。

您的值必须已经存在于其他地方,它很可能是一个向量。

std::any_of在迭代器上运行。

C++中的迭代器是范围,这两个值告诉您范围的开始位置和结束位置。

大多数C++标准模板库集合(包括std::vector(都支持迭代器 API,因此您可以在它们上使用std::any_of

为了一个完整的示例,让我们检查一个向量是否包含42在顶部方式,只是为了使用std::any_of.

由于我们只想检查向量中的值是否存在而不更改任何内容(std::any_of不会修改集合(,因此我们使用返回constantbeginvectorend.cbegin().cend(),这些对std::any_of很重要,因为它必须遍历整个向量以检查是否至少有一个值与给定谓词匹配。

最后一个参数必须是一元谓词,这意味着它是一个函数,接受单个参数,并返回给定参数是否符合某些条件。

简而言之,std::any_of用于检查集合中是否至少有一个值,该值具有您关心的某些属性。

法典:

#include <algorithm>
#include <iostream>
#include <vector>
bool is_42(int value) {
return value == 42;
}
int main() {
std::vector<int> vec{
1, 2, 3,
// 42 // uncomment this
};
if(std::any_of(vec.cbegin(), vec.cend(), is_42)) {
std::cout << "42 is in vec" << std::endl;
} else {
std::cout << "42 isn't in vec" << std::endl;
}
}

正如用户@a.abuzaid所述,您可以为此创建自己的方法。然而,他们提供的方法在答复的评论中陈述的一些方面有所欠缺。到目前为止,我真的无法理解std::any_of,只是决定创建这个模板:

template <typename Iterable, typename type>
bool any_of(Iterable iterable, type value) {
for (type comparison : iterable) {
if (comparison == value) {

return true;
}
}
return false;
}

这里使用的示例是if (any_of(myVectorOfStrings, std::string("Find me!"))) { do stuff },其中iterable是字符串的向量,value是字符串"找到我!

您可以创建一个函数,将x与其他两个数字进行比较,以检查它们是否相同

bool anyof(int x, int y, int z) {
if ((x == y) || (x == z))
return true;
}

然后在主函数中,您可以像这样调用函数:

if (anyof(x, 1, 2))
cout << "Matches a number";