初始化包含带有lambda的std :: function的类 [英] Initialize class containing a std::function with a lambda
问题描述
我通过以下方式创建了一个包含 std :: function
的模板类:
I created a template class containing a std::function
as a member the following way:
template<typename Ret, typename... Args>
class Foo
{
private:
std::function<Ret(Args...)> _func;
public:
Foo(const std::function<Ret(Args...)>& func):
_func(func)
{}
};
为了不必指定传递函数的参数和返回类型, code> make_foo 重载:
In order not to have to specify the arguments and return type of the passed function, I created some make_foo
overloads:
template<typename Ret, typename... Args>
auto make_foo(Ret (&func)(Args...))
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
template<typename Ret, typename... Args>
auto make_foo(const std::function<Ret(Args...)>& func)
-> Foo<Ret, Args...>
{
return { func };
}
但是,我无法创建 make_foo
重载,它将lambda作为参数:
However, I was unable to create a make_foo
overload that takes a lambda as parameter:
template<typename Ret, typename... Args>
auto make_foo(??? func)
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
我找不到一种方法来获得返回类型和参数类型从lambda自动推导。是否有一个惯用的方法来解决这个问题?
I just can't find a way to have the return type and argument types automatically deduced from the lambda. Is there an idiomatic way to solve such a problem?
推荐答案
好的,所以我以为我会死, do itç_ç
Ok, so I thought I would die, but I finally managed to do it ç_ç
首先,我使用常用的索引。因为我没有官方的,我使用了几个月前写的旧索引:
First, I used the usual indices. Since I do not have the official ones, I used old indices I wrote some months ago:
template<std::size_t...>
struct indices {};
template<std::size_t N, std::size_t... Ind>
struct make_indices:
make_indices<N-1, N-1, Ind...>
{};
template<std::size_t... Ind>
struct make_indices<0, Ind...>:
indices<Ind...>
{};
然后,我使用了一些 function traits 在StackOverflow上找到。他们很好,我认为他们相当于Boost库链接在注释:
Then, I used some function traits found somewhere on StackOverflow. They are nice, and I think that they are equivalent to the Boost library linked in the comments:
template<typename T>
struct function_traits:
function_traits<decltype(&T::operator())>
{};
template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
using result_type = Ret;
template<std::size_t N>
using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
然后,我能够写一个合适的 make_foo
函数及其实现函数,因为它们都需要使用索引。注意,这很简单:
Then, I was able to write a proper make_foo
function and it implementation function, since both are required to use indices. Be careful, it's plain ugly:
template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
-> Foo<
typename function_traits<typename std::remove_reference<Function>::type>::result_type,
typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}
template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
-> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
return make_foo_(std::forward<Function>(func), Indices());
}
代码不知怎么丑陋和不可读,但它绝对有效。希望它不依赖于一些实现定义的行为。此外,感谢所有的您的建议,它帮助! :)
The code is somehow ugly and unreadable, but it definitely works. Hope it does not rely on some implementation-defined behaviour now. Also, thanks all for your advice, it helped! :)
int main()
{
auto lambda = [](int i, float b, long c)
{
return long(i*10+b+c);
};
auto foo = make_foo(lambda);
std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}
a href =http://coliru.stacked-crooked.com/a/f3c026d881096320 =nofollow> live example :)
这篇关于初始化包含带有lambda的std :: function的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!