Хранение объекта boost :: function с переменным количеством аргументов - PullRequest
0 голосов
/ 20 апреля 2020

Я пытаюсь создать структуру, которая хранит любой метод. Позже я могу вызвать 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 будет хранить его для личного использования.

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

error: в объявлении 'typename boost :: enable_if_ c <(! Boost :: is_integral :: value), boost :: function &> :: type boost :: function :: operator = (Functor) '

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

В следующей строке:

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 аргументов.

0 голосов
/ 20 апреля 2020

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

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

#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';
}
...