std::d istance 在给定 std::find 返回的迭代器时提供过去的结束索引

std::distance provide a past the end index when given an iterator returned by std::find

提问人:NaturalDemon 提问时间:9/8/2023 最后编辑:Guillaume RacicotNaturalDemon 更新时间:9/9/2023 访问量:84

问:

这是我目前正在处理的一段豁免代码。 似乎按预期完成工作,但总是返回 3,我尝试了各种配置或前面有问题。 我希望根据字符串的结尾方式获得正确的数组索引。std::findstd::distanceitstd::find

it打印地址。

const auto b = {"uF", "nF", "pF"}; 

std::string str("1.0uF");  // test string.   
//std::string str("1.0nF");  // test string.
//std::string str("1.0pF");  // test string.

auto it = std::find(b.begin(), b.end(), str);
debug  << "b has type: " << typeid(it).name() << '\n';
// b has type:  PKPKc
debug << "index: " << std::distance(b.begin(), it) <<'\n'; //*(*it) << '\n';
C++ 迭代器 C++17 标准

评论

4赞 user4581301 9/8/2023
注意:正在制作一个 ,而不是一个数组const auto b = {"uF", "nF", "pF"};initializer_list
1赞 NathanOliver 9/8/2023
find工作不正常。 将始终具有与类型相同的值,永不更改。它的价值观会发生变化。您需要与typeid(it).name()itend()
3赞 Retired Ninja 9/8/2023
find没有找到,因为它不存在,所以返回结束迭代器,从一开始就是 3。godbolt.org/z/7hsEeWdM91.0uf
0赞 user4581301 9/8/2023
关于 . 不保证你会得到一个人类可读的名字。它甚至不能保证两种不同的类型不会具有相同的名称。这不是很有用。如果您只想看一眼,通常可以使用 IDE调试器来揭示实际推断的类型。typeid(it).name()name
0赞 NaturalDemon 9/8/2023
@NathanOliver我想看看它是什么类型,看看我正在做的动作是否适用。

答:

3赞 Guillaume Racicot 9/8/2023 #1

std::find()用作比较器,因此字符串需要与要找到的元素完全匹配。operator==

你要找的是,例如:std::find_if()

auto ends_with(std::string const& str, std::string const& suffix) -> bool {
    if (str.length() < suffix.length()) {
        return false;
    }

    return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
}


auto main() -> int {
    using namespace std::literals; // for the 's' suffix

    const auto b = std::array{"uF"s, "nF"s, "pF"s}; 

    std::string str("1.0uF");  // test string.   
    //std::string str("1.0nF");  // test string.
    //std::string str("1.0pF");  // test string.

    // always std::string::iterator
    auto it = std::find_if(
        b.begin(), b.end(),
        [&](std::string const& e) {
            return ends_with(str, e);
        }
    );

    if (it != b.end()) {
        // found    
        debug << "index: " << std::distance(b.begin(), it) <<'\n'; //*(*it) << '\n';
    } else {
        // not found, distance is one past the end
    }
}

您可能会注意到,它不会在运行时推断类型。C++ 中的所有类型,无论您是否使用,都是固定的,就像您手写一样。你只需要根据你的需要编写正确的逻辑。autoauto

只有数组可能会令人困惑,因为它默认是推导的。使用可以解决这个问题。std::initializer_liststd::array

评论

0赞 Jan Schultke 9/8/2023
这可能应该使用而不是使用原始指针。这也可以通过以下方式完成std::array<std::string_view, 3>std::array{"uF"sv, "nF"sv, "pF"sv}
0赞 Guillaume Racicot 9/8/2023
@JanSchultke最有可能的,但我想做最小的改变。
0赞 user17732522 9/8/2023
// b has type: PKPKc现在可能会也可能不会有所不同,但目前尚不清楚 OP 为什么会看它。
0赞 Jan Schultke 9/8/2023
如果您依赖 C++ 20 的 .或者,如果您在此答案中不依赖 C++20,那么最好为旧版本提供替代方案。std::ranges::find_ifstd::basic_string::ends_with
1赞 Guillaume Racicot 9/8/2023
@NaturalDemon我添加了一个 ends_with 的实现,并使答案与 C++11 兼容