C ++ распространенный способ получить перегруженный указатель на функцию-член

size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
0
задан user2525536 3 March 2019 в 15:03
поделиться

3 ответа

Чтобы разрешить сохранение функций с аналогичными объявлениями в одной переменной std::function .

Функция с одним параметром:

std::function< int(int) > func_1_param;

func_1_param = static_cast< int (*)(int) >(&A::stat);
cout << "int(int)->" << func_1_param(1) << endl;

using  std::placeholders::_1;

func_1_param = std::bind(static_cast< int (A::*)(int) >(&A::mem), &a, _1);
cout << "int(int)->" << func_1_param(1) << endl;

Функция с 2 параметрами;

std::function< int(int, int) > func_2_param;

func_2_param = static_cast< int (*)(int, int) >(&A::stat);
cout << "int(int, int)->" << func_2_param(1, 2) << endl;

using  std::placeholders::_1;
using  std::placeholders::_2;

func_2_param = std::bind(static_cast< int (A::*)(int, int) >(&A::mem), &a, _1, _2);
cout << "int(int, int)->" << func_2_param(1, 2) << endl;

Вместо использования std::bind можно использовать лямбду.

0
ответ дан Robert Andrzejuk 3 March 2019 в 15:03
поделиться

Если вам нужно иметь возможность обрабатывать выражение &A::x одинаково, независимо от того, является ли x статическим или нестатическим членом A (и он может быть перегружен), тогда вам нужно передать это через какую-то другую перегруженную функцию, которая может принимать R(C::*)(Ts...) или R(C::*)(Ts...)const или R(*)(Ts...) и отправлять соответственно. Примерно так:

template <typename... Ts>
struct UniformResolver {
    template <typename C, typename R>
    constexpr auto operator()(R (C::*func)(Ts...)) const { return resolveMember(func); }
    template <typename C, typename R>
    constexpr auto operator()(R (C::*func)(Ts...) const) const { return resolveMember(func); }
    template <typename R>
    constexpr auto operator()(R (*func)(Ts...)) const { return resolveStatic(func); }
private:
    template <typename F>
    constexpr auto resolveMember(F func) const {
        return [func](auto&&... args) {
            return std::invoke(func, std::forward<decltype(args)>(args)...);
        };
    }
    template <typename F>
    constexpr auto resolveStatic(F func) const {
        return [func](auto&&, auto&&... args) {
            return std::invoke(func, std::forward<decltype(args)>(args)...);
        };
    }
};
template <typename... Ts>
constexpr UniformResolver<Ts...> uresolve {};

Это дает вам шаблон вызываемого объекта uresolve, который адаптирует указатель вашей функции, возвращая вызываемый объект, который можно вызывать единообразным образом и который делегирует указателю вашей функции. Вот как вы бы это использовали:

struct A {
    int mem(int a) const { return a * 2; }
    int mem(int a, int b) const { return a + b; }
    static int stat(int a) { return a * 2; }
    static int stat(int a, int b) { return a + b; }
};

int main() {
    A a;
    auto mem1 = uresolve<int>(&A::mem);
    auto mem2 = uresolve<int, int>(&A::mem);
    auto stat1 = uresolve<int>(&A::stat);
    auto stat2 = uresolve<int, int>(&A::stat);

    std::cout << mem1(a, 1) << '\n';
    std::cout << mem2(a, 1, 2) << '\n';
    std::cout << stat1(a, 1) << '\n';
    std::cout << stat2(a, 1, 2) << '\n';
}

Живая демо

0
ответ дан Oktalist 3 March 2019 в 15:03
поделиться

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

#include <iostream>


using namespace std;


struct A {
    int mem(int a) {
        return a * 2;
    };
    int mem(int a, int b) {
        return a + b;
    }
    static int stat(int a) {
        return a * 2;
    }
    static int stat(int a, int b) {
        return a + b;
    }
};


static A a;


int main() {
    typedef int(*type1)(int);
    typedef int(*type2)(int, int);

    cout << "a.mem(1) -> " << a.mem(1) << endl;
    cout << "a.mem(1, 2) -> " << a.mem(1, 2) << endl;
    cout << "A::stat(1) -> " << A::stat(1) << endl;
    cout << "A::stat(1, 2) -> " << A::stat(1, 2) << endl;
    cout << "a.stat(1) -> " << a.stat(1) << endl;
    cout << "a.stat(1, 2) -> " << a.stat(1, 2) << endl;

    cout << "----------------------------------" << endl;

    type1 aMem1 = [] (int a0) -> int { return a.mem(a0); };
    cout << "aMem1(1) -> " << aMem1(1) << endl;
    type2 aMem2 = [] (int a0, int a1) -> int { return a.mem(a0, a1); };
    cout << "aMem2(1, 2) -> " << aMem2(1, 2) << endl;
    type1 stat1 = [] (int a0) -> int { return A::stat(a0); };
    cout << "stat1(1) -> " << stat1(1) << endl;
    type2 stat2 = [] (int a0, int a1) -> int { return A::stat(a0, a1); };
    cout << "stat2(1, 2) -> " << stat2(1, 2) << endl;
    type1 aStat1 = [] (int a0) -> int { return a.stat(a0); };
    cout << "aStat1(1) -> " << aStat1(1) << endl;
    type2 aStat2 = [] (int a0, int a1) -> int { return a.stat(a0, a1); };
    cout << "aStat2(1, 2) -> " << aStat2(1, 2) << endl;

    return 0;
}

См. live [111 ] пример.

Это позволяет использовать исходную проблему, используя то же соглашение о вызовах, что и для пользователя. Это означает, что если пользователь может вызывать функцию-член (статическую или нет) таким образом, мы также используем то же соглашение о вызовах. Можно использовать указатели на функции-члены, используя вместо этого прокси-класс. Для меня лямбда-подход работал лучше.

0
ответ дан user2525536 3 March 2019 в 15:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: