如果不使用任何类型的帮助模板来确定此处的参数列表,我认为无法继续!
所以下面的解决方案还是基于Is it possible to figure out the parameter type and return type of a lambda?
对于像 lambdas 这样的函数指针和可调用类,它只需要一个专门的模板实例。
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 很有帮助。
提示:
不能使用通用 lambda,因为如果调用 lambda 的参数未知,那么如何“自动”确定参数。通过调用指定参数并获取返回类型非常容易,但是传递泛型 lambda 或具有重载调用运算符的对象需要指定应该使用哪些函数/方法。因此,如果您需要类对象中的泛型 lambda 或重载方法,只需手动指定参数!任何语言都不会有任何技巧可以让您给出一组可选调用,并在没有其他信息可用的情况下自动确定应该使用哪个调用。如前所述:如果调用的参数存在,只需使用它们!
备注:
如果您使用此解决方案,您只会为所有具有相同参数的函数调用设置一个模板实例,这可能会节省一些内存;)但它使用 std::function 来存储可调用对象,这需要一些运行时间......您现在有两种结果不同但都可用的解决方案;)