mem_fn to function of member object
Asked Answered
B

3

2

I was tinkering around with the std::mem_fn and couldn't manage to bind it to data/functions of an member of a struct (one layer deeper).

I hope that the code shows the problem better than I can describe it, because I'm not familiar with the terminology.

#include <functional>

struct Int
{
    Int(int _x = 0) : x(_x) {}
    int GetInt() const { return x; }
    int x;
};

struct IntWrapper
{
    IntWrapper(int _x = 0) : test(_x) {}
    int GetWrappedInt() const { return test.GetInt(); }
    Int test;
};

int main()
{    
    IntWrapper wrapper{ 123 };

    auto x = std::mem_fn(&IntWrapper::GetWrappedInt);
    //auto y = std::mem_fn(&IntWrapper::test.GetInt); // ERROR
    //auto z = std::mem_fn(&IntWrapper::test.x); // ERROR

    int a = x(wrapper);
    //int b = y(wrapper);
    //int c = z(wrapper);

    //std::cin.ignore();

    return 0;
}

The error message is the following:

error C2228: left of '.GetInt' must have class/struct/union
error C2672: 'std::mem_fn': no matching overloaded function found
error C3536: 'y': cannot be used before it is initialized
error C2064: term does not evaluate to a function taking 1 arguments

Question: Is it possible to make these binds? Do I need std::bind for this?

Borderer answered 19/6, 2017 at 8:31 Comment(3)
Lambda is a good alternative too: y = [](const IntWrapper& w){ return w.test.x; };Apostil
This is not a forum, but a Q&A site. You asked a question and received an answer. If you have a followup question, post separately (you may link back here). I rolled back your edit to follow this etiquette, and you should re-accept the answer which applied to the original question.Conferral
Yeah, I wasn't sure. Sorry.Borderer
S
3

According to the specification, std::mem_fn() takes as argument a member function pointer, i.e.

auto y = std::mem_fn(&Int::GetInt);
auto b = y(wrapper.test);

As far as I'm aware, std::mem_fn() is more or less obsolete, since lambda expressions. For example

auto y = [](IntWrapper const&wrapper) { return wrapper.test.GetInt(); };
auto b = y(wrapper);    // note: no need to get hold of member 'test'
Stoner answered 19/6, 2017 at 8:40 Comment(3)
I have a follow-up question now. Should I make a new Question for this or should I post it here?Borderer
Depends how independent a question it is. But a new question is okay.Stoner
https://mcmap.net/q/1331062/-mem_fn-to-mem_fn-of-member already asked :)Borderer
T
2

Your syntax is wrong, &IntWrapper::test is a pointer to member.

I've never seen &IntWrapper::test.GetInt, I don't even know how it is getting parsed.

Perhaps this is what you want

auto y = std::mem_fn(&decltype(IntWrapper::test)::GetInt);
auto b = y(wrapper.test);
Trebuchet answered 19/6, 2017 at 8:42 Comment(6)
Nice use of decltype to force reliance on the member. Although I'm not sure about the syntax being valid.Conferral
With all due respect to what a single online compiler does, I'd be more convinced by a standard quote. I'm looking myself however.Conferral
@StoryTeller Oh, you mean rigorously, misunderstood :P I don't have a quote, but I'd guess that is correct simply by intuition and what it means. And boy you found it fastTrebuchet
This looks promising, but somehow VS doesn't seem to like it.Borderer
@ThomasB. - VS doesn't like lots of things that are perfectly valid C++. I'd recommend a better compiler :PConferral
Or a pair of glasses for me. Got it now. Thanks!Borderer
T
2

Since anyway the return type of std::mem_fn is unspecified, I simply see no reason why using it instead of some lambda function:

auto x = [&wrapper]{  return wrapper.GetWrappedInt(); };
int a = x();

Or:

auto x = [](const IntWrapper& wrapper){ return wrapper.GetWrappedInt(); };
int a = x(wrapper);

I even think these are better since the compiler can have better optimization opportunities.

Tallinn answered 19/6, 2017 at 8:43 Comment(2)
About your claim of optimization opportunities, is it something to do with std::mem_fn?Trebuchet
I have edited the original question, which shows the actual issue that I'm facing.Borderer

© 2022 - 2024 — McMap. All rights reserved.