Я пытаюсь реализовать вектор, представляющий список объектов TimedCallback, которые наследуются от базового класса.
Они содержат некоторые основные переменные, а также указатель на функцию, которая является основной функцией.
Функция должна иметь возможность возвращать любой тип и иметь любые параметры.
Я передаю их как лямбды в функции, никаких проблем пока нет.
Это соответствующий код:
std::vector<std::unique_ptr<TimedCallbackBase>> m_TimerCallbackList;
struct TimedCallbackBase {
TimedCallbackBase() = default;
virtual ~TimedCallbackBase() = default;
template<typename T> T run()
{
return dynamic_cast< TimedCallback<T> & >(*this).Run();
}
template<typename T> std::string name()
{
return dynamic_cast< TimedCallback<T> & >(*this).Name;
}
template<typename T> TaskTimer time()
{
return dynamic_cast< TimedCallback<T> & >(*this).Time;
}
template<typename T> int repeatcount()
{
return dynamic_cast< TimedCallback<T> & >(*this).RepeatCount;
}
};
template <typename Fu>
struct TimedCallback : TimedCallbackBase {
TimedCallback(const std::string& name, const std::string& time, Fu f, int r) : Name(name), Run(f), Time(time), RepeatCount(r) {}
std::string Name;
Fu Run;
TaskTimer Time;
int RepeatCount;
};
template<typename Fu>
void Schedule(const std::string& name, const std::string& time, Fu f, int repeatCount = 0) {
TimedCallback cb(name, time, f, repeatCount);
if (!vec_contains(m_TimerCallbackList, cb)) {
m_TimerCallbackList.push_back(cb);
}
else { Global->Log->Warning(title(), "Callback '"+name+"' already exists."); }
}
Моя проблема в этом методе. Я не могу правильно запустить указатели функций.
void _RunTimers() {
if (m_TimerCallbackList.size() > 0) {
for (auto &t : m_TimerCallbackList) {
if (t != nullptr) {
std::string _name = t.get()->name(); // wrong syntax, or signature?
TaskTimer _time = t.get()->time();
int _repeatcount = t.get()->repeatcount();
//auto _run = t.get()->run(); ??
Global->t("Callback name: " + _name);
Global->t("Callback time: " + _time.GetRealTimeAsString());
Global->t("Callback count: " + its(_repeatcount));
}
}
}
else { Global->Log->Warning(title(), "No timed tasks to run at this time."); }
}
Я собираюсь использовать код, подобный следующему:
Task->Schedule("testTimer", "10sec", [&]{ return Task->Test("I'm a 10sec timer."); });
_RunTimers();
Я чувствую, что довольно далеко не правильно делаю.
Я не хочу указывать какие-либо шаблоны для _RunTimers (); метод.
Пожалуйста, помогите мне понять, как это возможно.
Редактировать:
Я имею в виду, я думаю, что вполне возможно просто определить группу typedefs в соответствии с
using int_func = std::function<int()>;
для каждого возможного случая, а затем перегрузить мой объект-обертку, но я искал что-то более динамичное и защищенное от изменений.
Редактировать 2: После внесения предложенных изменений
Примечание: я переименовал методы ради неясности.
(Метод Test () здесь не включен, он просто выполняет std :: cout строкового параметра)
главный:
Callback myCallback = make_callback(&TaskAssigner::Test, "I'm a 5sec timer.");
Task->ScheduleJob("timer1", "5sec", myCallback, -1);
Task->RunScheduledJobs();
Утилиты:
typedef double RetVal;
typedef std::function<RetVal()> Callback;
template <class F, class... Args>
Callback make_callback(F&& f, Args&&... args)
{
auto callable = std::bind(f, args...); // Here we handle the parameters
return [callable]() -> RetVal{ return callable(); }; // Here we handle the return type
}
struct TimedCallback {
TimedCallback(cstR name, cstR time, Callback f, int r)
: Name(name), Run(f), Time(time), RepeatCount(r) {}
RetVal operator()() const { return Run(); }
bool operator==(const TimedCallback& other) {
if (Name == other.Name && RepeatCount == other.RepeatCount) { return true; }
return false;
}
const bool operator==(const TimedCallback& other) const {
if (Name == other.Name && RepeatCount == other.RepeatCount) { return true; }
return false;
}
std::string Name;
Callback Run;
TaskTimer Time;
int RepeatCount;
};
TaskAssigner .h:
void ScheduleJob(const std::string& name, const std::string& time, const Callback& func, int repeatCount = 0);
void RunScheduledJobs();
std::vector<TimedCallback> m_TimerCallbackList;
TaskAssigner.cpp:
void TaskAssigner::ScheduleJob(const std::string& name, const std::string& time, const Callback& func, int repeatCount) {
TimedCallback cb(name, time, func, repeatCount);
if (!vec_contains(m_TimerCallbackList, cb)) {
m_TimerCallbackList.emplace_back(cb);
}
else { Global->Log->Warning(title(), "Callback '" + name + "' already added."); }
}
void TaskAssigner::RunScheduledJobs() {
if (m_TimerCallbackList.size() > 0) {
for (auto &t : m_TimerCallbackList)
{
RetVal value = t();
//Global->t("Callback result: " + std::to_string(value));
Global->t("Callback name: " + t.Name);
Global->t("Callback time: " + t.Time.GetRealTimeAsString());
Global->t("Callback count: " + its(t.RepeatCount));
}
}
else { Global->Log->Warning(title(), "No timed tasks to run at this time."); }
}
Текущая проблема:
Компилятор говорит: C3848: выражение, имеющее тип 'const std :: _ Bind , const char (&) [18]>' потеряло бы некоторые const-volatile квалификаторы для вызова .....
Я пытался исследовать, и некоторые упоминали ошибку с VS 2013, связанную с bind и auto. Решения включают ввод подписи, а не ее автоматическое изменение, или удаление / добавление правильного const (?). Не уверен, что это та же ошибка или моя реализация все еще неверна.
(Ошибка: https://stackoverflow.com/a/30344737/8263197)
Я не уверен, как именно я могу заставить RetVal поддерживать любое значение с этим typedef.
Я пытался
template<typename T>
struct CallbackReturnValue {
CallbackReturnValue(T v) : value(v) {}
T value;
};
но тогда мне все равно придется шаблонизировать другие методы поддержки. Что я здесь ошибаюсь?