簡體   English   中英

初學者如何使用 std::any_of?

[英]How to use std::any_of for a beginner?

我想將一個值與其他幾個值進行比較,並檢查它是否與這些值中的至少一個相匹配,我假設它會是這樣的

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 個參數(一元)並返回一個 bool(謂詞)。

為了讓std::any_of做你想做的事,你必須把你的值放在一個集合中,並將x放在UnaryPredicate

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 in over top,只是為了使用std::any_of

由於我們只想檢查 vector 中的值是否存在而不改變任何東西( std::any_of不修改集合),我們使用.cbegin().cend()返回constant beginvector end ,那些對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是字符串“Find me”。 .

例如,您可以創建一個函數,將 x 與其他兩個數字進行比較以檢查它們是否相同

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

然后在您的 main 中,您可以像這樣調用該函數:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM