2

I was trying to get "more fluent" with function pointer manipulation and I've got an issue with passing a member function to std::function when there are two overload: const and non-const. Based on other stackoverflow posts, I eventually succeeded, using static_cast but it's all but readable.
Here is a dummy working example. The core of the issue is wrapping two member-function overloads (const and non-const):

#include <functional>

struct dummy {
    int val = 42;
    int get() const { return val; }
    int& get() { return val; }
};

int main() {
    dummy obj;
    // std::function<int& (dummy &)> f = &dummy::get;
    // std::function<int (dummy const &)> f = &dummy::get;
    std::function<int&(dummy&)> f = static_cast<int& (dummy::*)()>(&dummy::get);
    std::function<int(dummy const&)> fc =
        static_cast<int (dummy::*)() const>(&dummy::get);

    // just to check that it works as expected
    f(obj) = 36;
    return fc(obj); // ok retrives 36
}

Live
Is there a simpler syntax?

4
  • 1
    Another option is not overloading get methods that way. Commented Oct 17, 2023 at 12:22
  • auto f = [&obj]() -> int& { return obj.get(); }; and auto fc = [&obj = std::as_const(obj)]() { return obj.get(); }; Commented Oct 17, 2023 at 12:22
  • With that said, getters are not always a good idea. And using classes or structures as simple containers of variables might not always be the best design choice. Commented Oct 17, 2023 at 12:23
  • @Someprogrammerdude As the struct name implied, it was just a dummy working example. The core of the issue is wrapping two overloads of a member function (const and non-const) Commented Oct 17, 2023 at 12:41

2 Answers 2

3

Addresses of overload set cannot be deduced for std::function, but you can write helpers to simplify the "cast":

template <typename Ret, typename C, typename...Ts>
auto overload(Ret(C::*m)(Ts...)) { return m; }

template <typename Ret, typename C, typename...Ts>
auto const_overload(Ret(C::*m)(Ts...) const) { return m; }

then

std::function<int& (dummy &)> f = overload(&dummy::get);
std::function<int (dummy const &)> fc = const_overload(&dummy::get);

Demo

Those helpers won't help to differentiate void C::foo(int)/void C::foo(float) though and would requires other helpers.

Sign up to request clarification or add additional context in comments.

1 Comment

This answer is equally acceptable. I'm afraid we cannot accept several answers so I made an arbitrary choice (arbitrary being the nice word for randomly). Sorry.
1

You can use a lambda expression:

std::function<int&(dummy&)> f = [](dummy& d) -> int& { return d.get(); };    
std::function<int(dummy const&)> fc = [](const dummy& d) { return d.get(); };

I didn't manage to convince gcc to accept the first line without explicitly specifiying int& return type tough.

Live

If you want to actaully stay with function pointers, I am not aware of something "simpler". Imho the static_cast is very clear about what is going on. It is possible to use type aliases to make it less verbose, but it will most certainly also be less readable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.