Home > Back-end >  How to perfectly forward multiple struct members
How to perfectly forward multiple struct members

Time:11-21

I'm looking to get some clarity on the correct way to forward multiple members from the same forwarding reference to a struct.

Example

Here's an example of forwarding two fields (one_field and another_field) to a class constructor (widget) from a forwarding reference argument info. This is how I previously thought we should do it:

template<typename Bundle>
auto make_widget(Bundle&& info) {
    return widget(std::forward<Bundle>(info).one_field, std::forward<Bundle>(info).another_field);
}

There is a discussion on reddit's C thread that lists 9 ways to forward struct member fields. This confirms that it is OK to use this idiom to forward individual member fields, but this seems problematic for multiple uses of forward.

FWD(t).field: forward t.field, and invalidates t and all its members

What concerns me is that my example therefore is incorrect, as all of the fields of info are invalidated by the initial std::forward<Bundle>(info). The subsequent field access of the second std::forward<Bundle>(info). So I am now unclear on the validity of the example above.

How should we be passing on multiple struct fields in a way which is theoretically and practically safe? I'm very much hoping it's not required to write a variant of std::forward which moves its argument depending on the semantics of the parent struct type.

References

Reddit discussion on single field members: https://www.reddit.com/r/cpp/comments/q4mchr/overview_of_different_ways_of_passing_struct/

Comment on multiple forwards: https://www.reddit.com/r/cpp/comments/q4mchr/comment/hfzsidd/ -- found this post suggesting this is OK "in practice" but given the subtlety of C bugs, I'm keen to know this is OK "in theory" as well! I'm hoping that since under the hood std::forward is a static_cast to an rvalue type the invalidation doesn't happen to the other fields as would happen if a move constructor was actually called.

Similar SO question (for a single member field): How to perfectly forward a struct member?

Thanks all.

CodePudding user response:

the forward you have already does the correct thing (i.e. forward the member as Bundle) and access a field is not like to invalidate the parent object.

template<typename Bundle>
auto make_widget(Bundle&& info) {
    return widget(
        std::forward<Bundle>(info).one_field,
        std::forward<Bundle>(info).another_field
    );
}

if you want, you can also use something like std::forward_like in c 23

template<typename Bundle>
auto make_widget(Bundle&& info) {
    return widget(
       std::forward_like<Bundle>(info.one_field),
       std::forward_like<Bundle>(info.another_field)
    );
}
  • Related