22

Consider the following code:

template<typename T> void foo(T&& some_struct)
{
    bar(std::forward</* what to put here? */>(some_struct.member));
}

In the case of forwarding the whole struct I would do std::forward<T>(some_struct). But how do I get the correct type when forwarding a member?

One idea I had was using decltype(some_struct.member), but that seems to always yield the base type of that member (as defined in the struct definition).

mic
  • 821
  • 6
  • 18

3 Answers3

15

Member access is value category preserving. If the object expression is an lvalue, so is the member access, otherwise it is an xvalue (like the result of std::move). So do member access on the result of forwarding the object.

std::forward<T>(some_struct).member
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
14

Member access does the right thing here: you just need std::forward<T>(some_struct).member.

Tested with:

template <class... >
struct check;

struct Foo {
    int i;
};

template <class T>
void bar(T &&f) {
    // fatal error: implicit instantiation of undefined template 'check<int &&>'
    check<decltype((std::forward<T>(f).i))>{};
}

int main() {
    bar(Foo{42});
}
Quentin
  • 62,093
  • 7
  • 131
  • 191
5

As explained by @StoryTeller, if you forward the struct then the member value catogory is preserved (I think this is important to keep in mind). But how do I get the correct type when forwarding a member? you could do something like this:

template <typename T>
void foo(T&& some_struct) {
    bar(std::forward<decltype(std::declval<T>().member)>(some_struct.member));
}

In this code the actual object that's being forwarded is the member and not the object. As forwarding is a just conditional move, you might want to look at this two articles: enter link description here enter link description here

K.Kaland
  • 61
  • 3
  • I like the two articles you linked. However, I don't really understand the point of the rest of the answer. It seems to contradict Louis Dionne's article, since if `member` is a reference, you'd be moving from the member when you probably should not do so. – Justin Feb 15 '19 at 15:00
  • @Justin You're absolutely right, you shouldn't, but if the member is not a shared object, moving it is perfectly safe( read the first arcticle). The snippet code is a possible solution to his question " But how do I get the correct type when forwarding a member?". I linked the two articles to point to the asker, that doing so my not be safe. – K.Kaland Feb 15 '19 at 15:59