我有很少的自定义类型将用作函数的不同参数:
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
还有许多函数返回functor包装器:
template <typename H>
auto foo (H h,
enable_if_t<is_same<typename result_of<H(A)>::type, bool>::value>* = 0)
{
return [h] (B x) { return h (A {}); };
}
这件事将H(A)仿函数转换为G(B)仿函数,转换输入参数B-> A(为简单起见未在此处实现)并用A调用H.
我有类似的转换器C-> B,D-> C,E-> D:
template <typename H>
auto foo (H h,
enable_if_t<is_same<typename result_of<H(B)>::type, bool>::value>* = 0)
{
return [h] (C x) { return h (B {}); };
}
template <typename H>
auto foo (H h,
enable_if_t<is_same<typename result_of<H(C)>::type, bool>::value>* = 0)
{
return [h] (D x) { return h (C {}); };
}
template <typename H>
auto foo (H h,
enable_if_t<is_same<typename result_of<H(D)>::type, bool>::value>* = 0)
{
return [h] (E x) { return h (D {}); };
}
现在我可以调用foo 4次并获得带有#34; E&#34;类型参数的函子,最后用参数#34来调用内部处理程序; A&#34;:
auto inner_handler = [] (A) -> bool { return false; };
auto f = foo (foo (foo (foo ( inner_handler ))));
f (E {});
我想要的是实现call_until函数,该函数将调用&#34; foo&#34;递归重载,直到结果函子的参数类型变为T。
让我们说从A到E的转换器的路径总是存在而且恰好是一个。换句话说,我喜欢表达式
auto f = call_until<E> ( inner_handler );
完全按照
工作auto f = foo (foo (foo (foo ( inner_handler ))));
我从以下内容开始:
template <typename Stop, typename Handler, typename Result>
struct call_until_helper
{
Handler handler_;
call_until_helper (Handler h) : handler (h) {}
};
template <typename Stop, typename Handler>
call_until_helper<Stop, Handler,
typename boost::function_traits<Handler>::result_type>
call_until (Handler handler)
{
return call_until_helper<Stop, Handler,
typename boost::function_traits<Handler>::result_type> (handler);
}
但是我遇到了编译错误,有点卡住了。我需要一些想法来实现这一点。
答案 0 :(得分:3)
您的近似问题是function_traits
需要函数类型,而不是lambda类型。要确定这一点,只需找到错误,提取导致它的语句,然后剥离类型并直接传递它们。
boost::function_traits< decltype( inner_handler ) >::result_type b = false;
无法编译。然后我检查了文档,是的,它需要一个函数类型,而不是一个lambda。 Lambda不是函数。
这是解决实际问题附近问题的草图。语法略有不同,因为我很懒。
这是fooify
。它表示单个对象中foo
的整个重载集:
struct fooify {
template<class...Args>
auto operator()(Args&&...args)const{
return foo(std::forward<Args>(args)...);
}
};
这是一种帮助器类型,在传递测试之前递归地将操作应用于输入:
template<class Action, template<class...>class test, class Arg, class=void>
struct repeat_until_helper {
using action_result = result_of_t< Action&(Arg) >;
auto operator()(Action&& action, Arg&&arg)const {
return repeat_until_helper<Action, test, action_result>{}(
std::forward<Action>(action),
action( std::forward<Arg>(arg) )
);
}
};
template<class Action, template<class...>class test, class Arg>
struct repeat_until_helper< Action, test, Arg,
std::enable_if_t< test<Arg>{} >
> {
auto operator()(Action&& action, Arg&&arg)const {
return std::forward<Arg>(arg);
}
};
这是一个使用上面帮助器的函数,所以我们只需要传入一种类型(测试),其余的都是推导出来的:
template<template<class...>class test, class Action, class Arg>
auto repeat_until( Action&& action, Arg&& arg) {
return repeat_until_helper< Action, test, Arg >{}( std::forward<Action>(action), std::forward<Arg>(arg) );
}
以下是使用E
rvalue调用的类型的测试:
template<class X, class=void>
struct can_be_called_with_E:std::false_type{};
template<class X>
struct can_be_called_with_E<X,
decltype(
void(
std::declval<X>()(std::declval<E>())
)
)
>:std::true_type{};
我们完成了。语法不同,但这只是一些整理工作。