Хранение объекта boost::function с переменным количеством аргументов

Чего я пытаюсь добиться, так это создать структуру, в которой хранится любой метод. Позже я могу вызвать struct_object.run() для запуска сохраненного метода.

Этот метод может возвращать любое значение и, самое главное, использовать любое количество параметров; однако я не могу обойти проблему «любого количества параметров».

Имейте в виду, следующий код даже не собирается, в основном потому, что я понятия не имею, каким должен быть правильный синтаксис.

ApplicationPair.h

template<typename T, typename... Args>
struct ApplicationPair
{
    ApplicationPair(boost::function<T()> func, Args... arguments )
    {
        _func = func(Args::arguments...);
    }

    ApplicationPair() = delete;

    void run(); 
    boost::function<T(Args...)> _func;
};

#endif

И затем, что я хотел бы сделать, это следующее:

main.cpp

template<typename T, typename... Args>
void ApplicationPair<T,Args...>::run()
{
    this->_func;
}

//TEST

int counter = 0;

void HelloWorld()
{
    std::cout << "HelloWorld\n";
}

void printNumber(int i)
{
    std::cout << "Print: " << i << std::endl;
}

void increaseCounter(int x)
{
   counter+=x;
}

int main()
{
    ApplicationPair<void> p1(HelloWorld);
    ApplicationPair<void> p2(printNumber, 5);
    ApplicationPair<void> p3(increaseCounter, 10);
    p1.run();
    p2.run();
    p3.run();
    return 0;
}

По сути, методы, которые я хочу сохранить, не должны быть изменены или адаптированы каким-либо образом: я хочу иметь возможность создавать любые методы, не заботясь о том, что struct ApplicationPair сохранит их для личного использования.

Все, что я получаю с этим, это длинная строка ошибок, например:

ошибка: в объявлении ‘typename boost::enable_if_c‹(! boost::is_integral::value), boost::function&>::type boost::function::operator=(Functor)’


person kn0bbulo    schedule 20.04.2020    source источник
comment
Не связано: если вы используете C++11 или более позднюю версию, вы можете использовать std::function< /a> вместо boost::function.   -  person Ted Lyngmo    schedule 20.04.2020
comment
@TedLyngmo да, я просто использую boost::function, потому что это то, что меня просят использовать на работе.   -  person kn0bbulo    schedule 20.04.2020
comment
как вы планируете вызывать функции, когда они могут иметь любое количество параметров? И как вы хотите использовать возвращаемые значения? this->_func; ничего не делает, вам нужно вызвать функцию   -  person 463035818_is_not_a_number    schedule 20.04.2020
comment
параметры уже переданы на построение? В этом случае вам нужно только хранить функции, которые не принимают параметров и привязывают параметры   -  person 463035818_is_not_a_number    schedule 20.04.2020
comment
Есть ли особая потребность в имени run? Если вы изменили его на operator(), вы можете использовать boost::function<void()> напрямую.   -  person Caleth    schedule 20.04.2020


Ответы (2)


В строке ниже:

ApplicationPair<void> p2(printNumber, 5);

вы должны указать все типы в списке аргументов шаблона, а не только void в качестве возвращаемого типа, также следует добавить int в качестве аргумента конструктора. Теперь args... пусто. Что случилось. То же самое с p3.

Сделайте конструктор шаблонным методом, принимая пакет параметров в качестве аргумента для вашего вызываемого объекта:

template<class F, class ... Args>
ApplicationPair(F&& func, Args... arguments )
{
    _func = boost::bind(std::forward<F>(func),arguments...);
}

тогда args... можно вывести при вызове конструктора. Ваш шаблон класса принимает только тип возвращаемого значения.

template<class Ret>
struct ApplicationPair {
    template<class F, class ... Args>
    ApplicationPair(F&& func, Args... arguments )
    {
        _func = boost::bind(std::forward<F>(func),arguments...);
    }
    ApplicationPair() = delete;
    void run() {
        this->_func();
    }
    boost::function<Ret()> _func;
};

В конструкторе boost::bind используется для привязки переданных параметров к вызываемому. Вы нигде не храните параметры, поэтому они должны быть связаны в функторе, созданном boost::bind.

Использование:

ApplicationPair<void> p1(HelloWorld);
ApplicationPair<void> p2(printNumber, 5);
ApplicationPair<void> p3(increaseCounter, 10);

Демо


Не используйте boost::bind, он может обрабатывать не более 9 аргументов.

person rafix07    schedule 20.04.2020
comment
Это идеально, именно то, что я искал. Мне придется немного изучить код, чтобы понять, как именно все работает (например, тот факт, что вы используете std::forward, который я, к сожалению, никогда раньше не использовал), но теперь у меня наконец есть правильно работающий код. СПАСИБО. ! - person kn0bbulo; 20.04.2020
comment
std::forward поддерживает категорию значения параметра - person Caleth; 20.04.2020

Вы уже получили ответ, но вот альтернатива С++ 17, способная вывести тип возвращаемого значения, а также типы аргументов функции с помощью руководства по выводу, делая как тип возвращаемого значения, так и типы аргументов частью типа ApplicationPair<>. Я решил хранить аргументы отдельно в файле std::tuple<Args...>.

В этом примере boost::function можно заменить на std::function на случай, если позже вы решите использовать стандарт:

#include <boost/function.hpp>
#include <iostream>
#include <type_traits>
#include <tuple>

template<typename T, typename... Args>
struct ApplicationPair {
    ApplicationPair() = delete;

    ApplicationPair(Func func, Args... args) : 
        _func(func),
        // store the arguments for later use
        arguments(std::make_tuple(std::forward<Args>(args)...))
    {}

    decltype(auto) run() {        // I'd rename this: decltype(auto) operator()()
        return std::apply(_func, arguments);
    }

    boost::function<T(Args...)> _func;
    std::tuple<Args...> arguments;
};

// deduction guide
template<typename Func, typename... Args>
ApplicationPair(Func, Args...) -> 
    ApplicationPair<std::invoke_result_t<Func, Args...>, Args...>;
int counter = 0;

void HelloWorld()
{
    std::cout << "HelloWorld\n";
}

void printNumber(int i)
{
    std::cout << "Print: " << i << std::endl;
}

int increaseCounter(int x) // changed return type for demo
{
   counter+=x;
   return counter;
}

int main()
{
    // full deduction using the deduction guide
    ApplicationPair p1(HelloWorld);
    ApplicationPair p2(printNumber, 5);
    ApplicationPair p3(increaseCounter, 10);
    p1.run();
    p2.run();
    std::cout << p3.run() << '\n';
    std::cout << p3.run() << '\n';
}
person Ted Lyngmo    schedule 20.04.2020