Перегрузка функции члена С++ с помощью & (амперсанд)
Как выбрать правильную функцию 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
}
Ответы
Ответ 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); };
Обратите внимание, что до сих пор вы получаете замыкания как типы, а не указатели на функции. Если вам нужны указатели на функции, что полезно, если вы хотите хранить разные функции-члены с одной и той же сигнатурой в массиве, вы можете применить закрытие к указателю функции (нормальный) через +
(см. здесь).
Насколько я могу видеть на данный момент, с вышесказанным вы можете сделать концептуально все, что вы можете сделать с помощью указателей от функции к члену, - за исключением, конечно, вызова процедуры, которая точно требует такого указателя. И это намного приятнее.