简体   繁体   中英

Get projected value from std::ranges algorithms

I am using algorithms from std::ranges ( max and max_element ) with a projection. Is it possible for the result to also be the projected value? Currently I have to call the projection function again on the returned value.

Example : Here I want the size of the longest string, but the algorithms return only the string or an iterator to it.

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;
}

Compiler Explorer

You're using an algorithm ( max / max_element ) on the original range, which can't do anything but give you an element/iterator into the range.

If you want just the projected values, do the projection (via a views::transform ) to get the lengths first, and then find the maximum of that

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

Here's a demo .


As mentioned in this answer , taking the address of std::string::size is not permitted, so you should use a lambda instead. In general though, taking a projection based on a member function works just fine, so long as it's not a std function.

Here I want the size of the longest string, but the algorithms return only the string or an iterator to it.

In fact, according to [namespace.std#6] :

Let F denote a standard library function ([global.functions]), a standard library static member function, or an instantiation of a standard library function template. Unless F is designated an addressable function, the behavior of a C++ program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer to F .

This is unspecified behavior since you are forbidden to extract the address of the string::size .

You can use views::transform to convert the original range to a range whose elements are the size value and then take the maximum value.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM