LINUX.ORG.RU

Как лучше храниь указатель на функцию и ее параметры внутри класса.

 , ,


1

4

Сейчас организую систему таймеров.
Хотелось узнать как правильно хранить указатель на функцию или метод вместе с параметрами с использование преимуществ C++11.

Вот нашел такой интересный код на просторах сети:

#include <functional>
#include <chrono>
#include <future>
#include <cstdio>

class later
{
public:
    template <class callable, class... arguments>
    later(int after, bool async, callable&& f, arguments&&... args)
    {
        std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...));

        if (async)
        {
            std::thread([after, task]() {
                std::this_thread::sleep_for(std::chrono::milliseconds(after));
                task();
            }).detach();
        }
        else
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(after));
            task();
        }
    }

};

void test1(void)
{
    return;
}

void test2(int a)
{
    printf("%i\n", a);
    return;
}

int main()
{
    later later_test1(1000, false, &test1);
    later later_test2(1000, false, &test2, 101);

    return 0;
}

Хотелось бы сохранить task в приватной переменной и сделать доступ к ее параметрам(возможность их изменить).

Возможностью хранить и изменять параметры интересуюсь в образовательных целях. Куда больше волнует вопрос простого хранения и вызова функций по стандарту 11 года.

ps. Кстати такой хак, как передача шаблону параметров без угловых скобок, доступен только в конструкторах?

★★★★★

Последнее исправление: deterok (всего исправлений: 1)

Хотелось бы сохранить task в приватной переменной и сделать доступ к ее параметрам(возможность их изменить).

А что мешает сделать отдельный класс-параметр? Типо пользователь его заполняет перед вызовом (со всеми проверками), а потом передаёт функции (там дополнительные проверки).

ИМХО вот это вот подражание printf(...) в 21 веке уже выглядит глупо.

ziemin ★★
()

Пример какой-то странный, там всё как будто не на своём месте. Но bind и function упомянуты, чего ещё не хватает? Просмотри по диагонали описание стандартной либы, не будут возникать вопросы, каким микроскопом гвоздь забить.

const86 ★★★★★
()
Ответ на: комментарий от ziemin

Предлагаешь написать интерфейс для таймеров, которые придется наследовать?

deterok ★★★★★
() автор топика

Хреновый таймер, его остановить нельзя.

zJes ★★
()

Байндишь параметры к функции, и хранишь функцию без параметров.

annulen ★★★★★
()

Принимай

typedef std::function<void(void)> Callback;
и сохраняй в своей приватной переменной. А там с ним уже что угодно делать можно.

Смысла у отложеных вызовов в возвращаемом значении всё равно нет.

tff
()

Такое можно сделать, но получается очень страшная наркомания.

Вот это, наверное, допиливается до нужного состояния с помощью этой статьи.

#include <iostream>
#include <tuple>
#include <memory>

template<class R, class ... Args>
struct task_holder 
{
    virtual R operator() (Args&&... args) const = 0;

    virtual ~task_holder()
    {
    }
};

template<class T, class R, class ... Args>
struct task_holder_impl : task_holder<R, Args...>
{
    task_holder_impl(T const& func)
    : func(func)
    { }

    R operator() (Args&&... args) const override
    {
        return func(std::forward<Args>(args)...);
    }

private:
    T const& func;
};

template <class... Args>
struct task;

template<class R, class ... Args>
struct task<R(Args...)>
{
    template<class T>
    task(T const& func, Args... args) 
    : holder(new task_holder_impl<T, R, Args...>(func)), arguments(std::make_tuple(args...))
    { }

    template<int N, class T>
    void set_argument(T const& val)
    {
        std::get<N>(arguments) = val;
    }

    R operator() ()
    {
// вот тут я остановился
    }

private:
    std::shared_ptr<task_holder<R, Args...>> holder;
    std::tuple<Args...> arguments;
};

void f(int a, int b)
{
    std::cout << a + b << std::endl;
}

int main() 
{
    task<void(int, int)> t(f, 1, 2);
    task<void(int, int)> t1([](int a, int b) { std::cout << a + b; }, 1, 2);


}

Кстати такой хак, как передача шаблону параметров без угловых скобок, доступен только в конструкторах?

Это не хак, это вывод типов шаблонной функции на основе передаваемых параметров

BlackHawk
()
Последнее исправление: BlackHawk (всего исправлений: 2)
Ответ на: комментарий от tff

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

deterok ★★★★★
() автор топика
Ответ на: комментарий от BlackHawk

Спасибо, статейка полезная.

deterok ★★★★★
() автор топика
Ответ на: комментарий от deterok

Функции-члены классов — это обычные функции, принимающие первым аргументом экземпляр класса.

    
struct A 
{
    void f() 
    {
        std::cout << "test\n";
    }
};

int main()
{
    A a;
    std::function<void()> func(std::bind(&A::f, a));
    func();
}
BlackHawk
()
Последнее исправление: BlackHawk (всего исправлений: 1)
Ответ на: комментарий от BlackHawk

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

Boy_from_Jungle ★★★★
()
Ответ на: комментарий от BlackHawk

Функции-члены классов — это обычные функции, принимающие первым аргументом экземпляр класса.

Зачем же врать? Тем более, что дальше ваш код работает с указателем на член, который не является обычным указателем.

anonymous
()
Ответ на: комментарий от deterok

Он тебя обманул. Хотя код верный.

anonymous
()
Ответ на: комментарий от anonymous

И правда, наврал, но не там. С точки зрения генерируемого ассемблерного кода это правда. Разве что у таких функций может быть другая конвенция вызова.

Другое дело, что в моем коде надо бы передавать указатель на экземпляр, иначе метод будет вызван у копии.

BlackHawk
()
Ответ на: комментарий от BlackHawk

С точки зрения генерируемого ассемблерного кода это правда.

Хм. Стандарт это не регламентирует. Реализация может передавать объекты как ей удобно.

forCe
()
Ответ на: комментарий от Boy_from_Jungle

А зачем таймеру что-то принимать если он должен только вызывать? Или ему у пользователя спрашивать с какими аргументами вызывать непосредственно перед вызовом?

tff
()
Ответ на: комментарий от tff

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

Boy_from_Jungle ★★★★
()
Ответ на: комментарий от Boy_from_Jungle

да я понятия не имею зачем тс шаблоны сюда приплёл )

tff
()

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

asaw ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.