C ++ 17 представил std :: invocable , но мне интересно решение C ++ 11-only. Моя первая мысль - использовать std :: result_of .
Мой текущий код выглядит следующим образом (SchedulingPolicy
является enum class
):
template<typename Function, typename... Args,
typename = typename std::result_of<Function&&(Args&&...)>::type>
int start(size_t stackSize, size_t queuedSignals, size_t signalActions,
uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function,
Args&&... args)
{
// main implementation
}
template<typename Function, typename... Args,
typename = typename std::result_of<Function&&(Args&&...)>::type>
int start(size_t stackSize, size_t queuedSignals, size_t signalActions,
uint8_t priority, Function&& function, Args&&... args)
{
return start(stackSize, queuedSignals, signalActions, priority,
SchedulingPolicy::roundRobin, std::forward<Function>(function),
std::forward<Args>(args)...);
}
template<typename Function, typename... Args,
typename = typename std::result_of<Function&&(Args&&...)>::type>
int start(size_t stackSize, uint8_t priority, Function&& function,
Args&&... args)
{
return start(stackSize, 0, 0, priority, SchedulingPolicy::roundRobin,
std::forward<Function>(function), std::forward<Args>(args)...);
}
template<typename Function, typename... Args,
typename = typename std::result_of<Function&&(Args&&...)>::type>
int start(size_t stackSize, uint8_t priority,
SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args)
{
return start(stackSize, 0, 0, priority, schedulingPolicy,
std::forward<Function>(function), std::forward<Args>(args)...);
}
Существует в основном одна основная реализация - со всеми возможными аргументами - и 3 обертки - у которых не все аргументы. Я использую SFINAE в аргументах шаблона - typename = typename std::result_of<Function&&(Args&&...)>::type
- иначе одна из оболочек вызывает бесконечную рекурсию. Кажется, это работает нормально, но я провел только очень ограниченное тестирование. Однако на cppreference я прочитал мотивацию обесценивания std::result_of
в пользу std::invoke_result
(кстати, есть информация, почему я использую ссылки на r-значения вместо std::result_of<Function(Args...)>
), что заставило меня задуматься, используется ли я правильно или может быть (в реальной жизни) ситуации, когда это на самом деле потерпит неудачу, даже если переданные аргументы верны? Мой сценарий использования передает все возможные «вызываемые объекты»: обычные функции, функции-члены, лямбды или функторы.