从 std::ranges 算法获取投影值

dav*_*ave 4 c++ c++20 std-ranges

我正在使用std::ranges(maxmax_element) 中的算法进行投影。结果有可能也是预测值吗?目前我必须对返回值再次调用投影函数。

示例:这里我想要最长字符串的大小,但算法仅返回字符串或迭代器。

int main()
{
    const std::vector<std::string> vec = {
        "foo",
        "hello",
        "this is a long string",
        "bar"
    };

    //r1 is a string. r2 is an iterator
    const auto r1 = std::ranges::max(vec, {}, &std::string::size);
    const auto r2 = std::ranges::max_element(vec, {}, &std::string::size);
    
    //I have to call size() again
    std::cout << r1 << '\n' << *r2 << '\n';
    std::cout << r1.size() << '\n' << r2->size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

编译器资源管理器

cig*_*ien 5

您在原始范围上使用算法 ( max/ max_element),该算法除了为您提供该范围中的元素/迭代器之外什么也做不了。

如果您只想要投影值,请先进行投影(通过 a views::transform)以获取长度,然后找到该值的最大值

auto const lens = std::views::transform(vec, &std::string::size);

const auto r1 = std::ranges::max(lens);
const auto r2 = std::ranges::max_element(lens);

std::cout << r1 << '\n' << *r2 << '\n';  // prints 21 21
Run Code Online (Sandbox Code Playgroud)

这是一个演示


正如这个答案std::string::size中提到的,不允许使用 的地址,因此您应该使用 lambda。但一般来说,基于成员函数进行投影就可以很好地工作,只要它不是 std 函数。


康桓瑋*_*康桓瑋 5

这里我想要最长字符串的大小,但算法仅返回字符串或迭代器。

事实上,根据[namespace.std#6]

F表示一个标准库函数 ([global.functions])、一个标准库静态成员函数或一个标准库函数模板的实例。除非F指定了 可寻址函数,否则如果 C++ 程序显式或隐式尝试形成指向 的指针,则其行为是未指定的(可能是格式错误的)F

这是未指定的行为,因为您被禁止提取string::size.

可以使用views::transform将原始范围转换为元素为大小值的范围,然后取最大值。

auto size = std::ranges::max(
              vec | std::views::transform([](auto& s) { return s.size(); }));
std::cout << size << '\n';
Run Code Online (Sandbox Code Playgroud)