Указатель на функцию хранится в классе - PullRequest
0 голосов
/ 22 октября 2018

Я хочу иметь возможность хранить указатель на функцию в структуре или классе, тогда я могу вызывать эту функцию при нажатии кнопки?вот что у меня есть:

struct INFO
{
    std::function<int(int, int)> call_back;
};

class YO
{
public:
    YO() {};
    ~YO() {};

    int SUM(int A, int B) { return A + B; }
};

int main()
{
    //std::function<int(int, int)> datFunc = SUM;
    INFO info;
    YO* yo = new YO();
    info.call_back = yo->SUM;

    //std::function<int(int, int)> func =;
    std::cout << info.call_back(10, 10) << std::endl;

    system("pause");
    return 0;
}

Я получаю ошибки:

Error   C3867   'YO::SUM': non-standard syntax; use '&' to create a pointer to member   FunctionPointertest 
Error   C2679   binary '=': no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion) FunctionPointertest 

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

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

std::function<int(YO*, int, int)> call_back;

И когда вы вызываете его:

info.call_back(&yo, 10, 10)
0 голосов
/ 24 октября 2018

Вот набор Variadic Template Classes, который позволит вам легко это сделать, если у вас есть C++17.Первый класс просто хранит универсальную версию std::function любого типа!Второй класс хранит первый класс через member function и будет register либо function pointer, function object или lambda.У этого также есть другой member function, который будет invoke это.В настоящее время я использую lambdas в этом примере.У меня есть два lambdas, 1 st берет два типа int, добавляет их и возвращает int, как в вашей проблеме выше.2 nd принимает два std::strings объединения их, затем выводит их на экран, но не возвращает никакого значения.Вы даже можете расширить это, сохранив std::vector<Functor<>> в классе драйверов.register_callback изменится незначительно, чтобы вставить их в вектор, а call_back у вас есть варианты.Вы можете либо вызвать их все за один раз, либо выполнить поиск по значению индекса, чтобы вызвать конкретное, но я оставлю это в качестве упражнения для вас.

#include <string>
#include <iostream>
#include <functional>

template<typename RES_TYPE, typename... ARG_TYPES>
struct Functor {
    std::function<RES_TYPE( ARG_TYPES... )> func_;
};

template<typename RES_TYPE, typename... ARG_TYPES>
class Driver {
private:
    Functor<RES_TYPE, ARG_TYPES...> functor;

public:
    Driver() = default;
    ~Driver() = default;

    void register_callback( const Functor<RES_TYPE, ARG_TYPES...> &func ) {
        functor = func;
    }

    RES_TYPE call_back( ARG_TYPES... args ) {
        return functor.func_( std::forward<ARG_TYPES>(args)... );
    }    
};    

int main() {
    // Function Type: int ( int, int );
    Functor<int, int, int> func;
    auto lambda = []( int a, int b ) { return a + b; };
    func.func_ = lambda;

    Driver<int, int, int> driver;
    driver.register_callback( func );
    int a = 3;
    int b = 5;
    std::cout << driver.call_back( a, b ) << '\n';
    std::cout << driver.call_back( 7, 5 ) << '\n';

    // Function Type: void ( string, string );
    Functor<void, std::string, std::string> func2;
    auto lambda2 = []( std::string str1, std::string str2 ) {
        str1 = str1 + " " + str2;
        std::cout << str1 << '\n';
    };

    Driver <void, std::string, std::string> driver2;
    func2.func_ = lambda2;
    driver2.register_callback( func2 );
    std::string str1 = "Hello";
    std::string str2 = "World";
    driver2.call_back( str1, str2 );
    driver2.call_back( "Generic", "Programming" );

    return 0;
}

Вывод:

8
12
Hello World
Generic Programming

Если вы заметили этот код здесь;нет необходимости связываться с указателями или динамической памятью.Об этом все заботятся, используя для нас std::function и классы по умолчанию dtors.

Я старался изо всех сил создать его с простотой, удобочитаемостью, делая его портативным и универсальным, насколько это возможно.,Я уверен, что могут быть сделаны некоторые улучшения, но я думаю, что это соответствует тому, что вы просите.

0 голосов
/ 22 октября 2018

Некоторые варианты сделать то, что вы хотите.Использование лямбды - лучшее решение.

void func() {
    INFO info;
    YO yo;
    YO* yo2 = new YO;
    info.call_back = [&yo](int a, int b) {
        return yo.SUM(a, b);
    };
    using namespace std::placeholders;
    info.call_back = std::bind(&YO::SUM, std::ref(yo), _1, _2);
    info.call_back = std::bind(&YO::SUM, yo2, _1, _2);
}

PS Обычно вы не хотите использовать new в c ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...