C++ member function overloading with & (ampersand)

How to pick the correct error() member function? Do I need to cast somehow?

using namespace std;

struct test
{
   int error();
   void error(int x);
   int fun();
};

int main() {
   auto f1 = &test::error; // how to pick the correct function?
   auto f2 = &test::fun; // works
}

Upvotes: 28

Views: 2517

Answers (5)

songyuanyao
songyuanyao

Reputation: 172994

Do I need to cast somehow?

Yes, you can use static_cast.

static_cast may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type, as in

std::for_each(files.begin(), files.end(),
              static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

So you can:

auto f1 = static_cast<int(test::*)()>(&test::error);
auto f2 = static_cast<void(test::*)(int)>(&test::error);

Upvotes: 28

davidhigh
davidhigh

Reputation: 15518

Here is the solution when you don't have the internet to read up the ugly function-pointer-to-member syntax:

auto err1 = [](test& t) { return t.error(); };
auto err2 = [](test& t, int x) { return t.error(x); };

Note that up to now you get closures as types and not function pointers. If you wanted function pointers, which is useful if you want to store different member functions with the same signature in an array, you can cast the closure to a (normal) function pointer via + (see here).

As far I can see at the moment, with the above you can do conceptually anything you can do with function-to-member-pointers -- except of course calling a routine which exactly requires such a pointer. And it's much nicer.

Upvotes: 1

template boy
template boy

Reputation: 10480

Since an answer is already given, I'll present a solution that's easier on the eyes. This situation is perfect for a macro if you don't want to write out the cast every time:

template<class T>
using test_type_t = T test::*;
#define TEST_CAST(T, F) static_cast<test_type_t<T>>(&F)

auto f1 = TEST_CAST(void(int), test::error);

Upvotes: 1

Joseph Thomson
Joseph Thomson

Reputation: 10433

You can just explicitly specify the member function pointer type.

int (test::*f1)() = &test::error;
void (test::*f2)(int) = &test::error;

Upvotes: 35

Bathsheba
Bathsheba

Reputation: 234825

You'll need to use a static_cast to disambiguate.

&test::error is not evaluable since the function is overloaded. The fact that you are assigning this to something marked auto is not immediately relevant.

One fix would be to use static_cast<int(test::*)()>(&test::error) or static_cast<void(test::*)(int)>(&test::error) as appropriate.

Then auto will work since there will be no ambiguity in the type deduction.

Upvotes: 3

Related Questions