Я не вижу способа продвинуться без использования какого-либо вспомогательного шаблона для определения списка параметров здесь!
Таким образом, следующее решение все еще основано на Можно ли выяснить тип параметраи возвращаемый тип лямбды?
Для наличия указателей на функции и вызываемых классов, таких как лямбда-выражения, требуется только специальный экземпляр шаблона.
template <typename CLASS>
struct function_traits_impl
: public function_traits_impl<decltype(&CLASS::operator())>
{};
template <typename CLASS, typename RET, typename... ARGS>
struct function_traits_impl< RET(CLASS::*)(ARGS...) const>
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template <typename CALLABLE > struct function_traits: public function_traits_impl< CALLABLE >{};
template< typename RET, typename... ARGS >
struct function_traits< RET(*)(ARGS...) >
{
using args_type = std::tuple<ARGS...>;
using ret_type = RET;
};
template < typename CLASS, typename CONTAINER, typename RET, typename ... ARGS> struct task;
template< typename CLASS, typename CONTAINER, typename RET, typename ... ARGS >
struct task< CLASS, CONTAINER, RET, std::tuple<ARGS...> >
{
using FUNC = std::function< RET(ARGS...)>;
FUNC func;
CONTAINER cont;
task( FUNC _func, CONTAINER& _cont): func{_func}, cont{_cont}
{
static_assert(
std::is_same<
//decltype( func( std::declval<PARMS>()...) ), // but is already known from given template parms!
RET,
typename CONTAINER::value_type
>::value,
"wrong return type, did not match with container type"
);
}
};
template <typename FUNC, typename CONTAINER >
task(FUNC, CONTAINER) -> task< FUNC, CONTAINER, typename function_traits<FUNC>::ret_type, typename function_traits<FUNC>::args_type>;
int Any( int ) { return 0; }
float WrongAny( int, int ) { return 1.1; }
int main()
{
std::vector<int> v;
//task t1{ [](int, int)->float { return 0; } , v}; // fails with assert as expected
task t2{ [](int, int)->int { return 0; } , v}; //Works!
task t3{ &Any , v}; // Works
//task t4{ &WrongAny, v }; fails as expected
}
Это решение просто использует определяемый пользователем выводруководство по пересылке найденных парм из черты, что полезно, так как вы также используете c ++ 17.
Подсказка: нельзя использовать общие лямбды, потому что, если параметры для вызова лямбды неизвестны, как вы можете определитьпараметры "автоматически".Довольно просто указать параметры с помощью вызова и получить тип возвращаемого значения, но при передаче обобщенной лямбды или объекта с перегруженным оператором вызова необходимо указать, какие из функций / методов следует использовать.Поэтому, если вам нужны общие лямбды или перегруженные методы в объектах классов, просто укажите параметры вручную!Ни в одном языке не может быть хитрости, которая позволяет вам давать набор необязательных вызовов и автоматически определять, какой вызов следует использовать, если другая информация недоступна.Как сказано: если присутствуют параметры для вызова, просто используйте их!
Примечание: если вы используете это решение, вы получите только один экземпляр шаблона для всех вызовов с тем же параметром, установленным для вызова функции, который может сохранитьнемного памяти;) Но он использует функцию std :: для хранения вызываемой функции, которая занимает некоторое время выполнения ... Теперь у вас есть два решения, которые отличаются по результатам, но оба пригодны для использования;)