История изменений
Исправление eao197, (текущая версия) :
Возможно я неправильно понял твою идею с использованием виртуального метода.
Очевидно, что так.
В TaskBase можно иметь просто виртуальный метод invoke
:
class TaskBase {
protected:
TaskBase() = default;
public:
virtual ~TaskBase() = default;
virtual void invoke() = 0;
};
А в наследниках просто переопределять этот invoke
:
template<typename Handler>
class Task : public TaskBase {
Handler fn_;
public:
template<typename Fn>
Task(Fn && fn) : fn_{std::forward<Fn>(fn)} {}
void invoke() override { fn_(); }
};
Зачем все эти приседания с указателем на функцию, дополнительные статические методы со static_cast внутри?
Ну и еще вам в TaskBase, скорее всего, потребуется виртуальный деструктор.
Возможно. Зависит от имплементации.
Зависит от имплементации очереди тасков. Т.к. если вы будете хранить unique_ptr<TaskBase>
, то проблемы из-за отсутствия виртуального деструктора практически гарантированы.
Если же будет использоваться shared_ptr<TaskBase>
, то подобных проблем можно избежать. Но это зависит от кривизны рук программиста.
Так что лучше сделать виртуальный деструктор. А отказаться от него только если профайлер покажет, что есть просадка производительности из-за этого виртуального вызова (что вряд ли будет иметь место в 99% случаев).
Исходная версия eao197, :
Возможно я неправильно понял твою идею с использованием виртуального метода.
Очевидно, что так.
В TaskBase можно иметь просто виртуальный метод invoke
:
class TaskBase {
protected:
TaskBase() = default;
public:
virtual ~TaskBase() = default;
virtual void invoke() = 0;
};
А в наследниках просто переопределять этот invoke
:
template<typename Handler>
class Task : public TaskBase {
Handler fn_;
public:
template<typename Fn>
Task(Fn && fn) : fn_{std::forward<Fn>(fn)} {}
void invoke() override { fn_(); }
};
Зачем все эти приседания с указателем на функцию, дополнительные статические методы со static_cast внутри?
Ну и еще вам в TaskBase, скорее всего, потребуется виртуальный деструктор.
Возможно. Зависит от имплементации.
Зависит от имплементации очереди сообщений. Т.к. если вы будете хранить unique_ptr<TaskBase>
, то проблемы из-за отсутствия виртуального деструктора практически гарантированы.
Если же будет использоваться shared_ptr<TaskBase>
, то подобных проблем можно избежать. Но это зависит от кривизны рук программиста.
Так что лучше сделать виртуальный деструктор. А отказаться от него только если профайлер покажет, что есть просадка производительности из-за этого виртуального вызова (что вряд ли будет иметь место в 99% случаев).