Подтвердить что ты не робот

Перегрузка функции члена С++ с помощью & (амперсанд)

Как выбрать правильную функцию error()? Мне нужно каким-то образом бросить?

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
}
4b9b3361

Ответ 1

Мне нужно каким-то образом бросить?

Да, вы можете использовать static_cast.

static_cast также может использоваться для устранения неоднозначности перегрузок функций путем преобразования функции-к-указателю в определенный тип, как в

std::transform(s.begin(), s.end(), s.begin(), static_cast<int(*)(int)>(std::toupper));

Итак, вы можете:

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

Ответ 2

Вы можете просто указать тип указателя функции-члена.

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

Ответ 3

Вам нужно использовать static_cast для устранения неоднозначности.

&test::error не оценивается, так как функция перегружена. Тот факт, что вы присваиваете это чему-то, помеченному auto, не имеет прямого значения.

Одним из исправлений будет использование static_cast<int(test::*)()>(&test::error) или static_cast<void(test::*)(int)>(&test::error) по мере необходимости.

Тогда auto будет работать, так как не будет двусмысленности в выводе типа.

Ответ 4

Поскольку ответ уже дан, я представлю решение, которое проще на глаза. Эта ситуация идеально подходит для макроса, если вы не хотите каждый раз выписывать кастинг:

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);

Ответ 5

Вот решение, когда у вас нет Интернета для чтения уродливого синтаксиса function-pointer-to-member:

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

Обратите внимание, что до сих пор вы получаете замыкания как типы, а не указатели на функции. Если вам нужны указатели на функции, что полезно, если вы хотите хранить разные функции-члены с одной и той же сигнатурой в массиве, вы можете применить закрытие к указателю функции (нормальный) через + (см. здесь).

Насколько я могу видеть на данный момент, с вышесказанным вы можете сделать концептуально все, что вы можете сделать с помощью указателей от функции к члену, - за исключением, конечно, вызова процедуры, которая точно требует такого указателя. И это намного приятнее.