Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

actions::transform fails on std::vector<T>, where T is a POD struct

Tags:

c++

range-v3

This works just fine:

    std::vector<int> ints{10, 20, 30};
    auto floats = ints | ranges::to_vector
        | ranges::actions::transform([](auto n){ return 1 / float(n); });

Now, given the following struct:

struct Foo
{
    int* hello;
    int num;
    float yes;
};

The equivalent code:

    std::vector<Foo> foo;
    auto bar = foo | ranges::to_vector
        | ranges::actions::transform([](auto f){ return f.hello; });

will not compile. Digging through the error message to find the actual error (with concepts enabled), you'd find that the invocable_ concept is not satisfied, which usually means the transform function can't be applied to Foo.

Why doesn't this work? Foo is trivially copyable just like int, so it makes no sense that a generic lambda wouldn't be applicable here.

Godbolt link: https://godbolt.org/z/YWWYxn4bq

like image 764
Romário Avatar asked Dec 06 '25 13:12

Romário


1 Answers

It doesn't work because you are using ranges::actions::transform. Range-v3 has two transform functions: one is an action that transforms the entire input range, producing a new range of the same type; the other produces a view object that transforms each element lazily upon iterating.

The action works on the int vector because the transformation returns values that can be assigned to integers, but in the second example, int* cannot be assigned to Foo values.

Note that this also means that your first example produces a std::vector<int> containing three zeroes. To obtain a std::vector<float> instead, use the transform view and place it before to_vector:

std::vector<float> floats = ints 
    | ranges::views::transform([](auto n){ return 1 / float(n); })
    | ranges::to_vector;
like image 89
sigma Avatar answered Dec 08 '25 04:12

sigma



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!