递归调用重载的c++函数
Recursive calling overloaded c++ functions
我有一些自定义类型将用作函数的不同参数:
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
还有一些函数是 returns 仿函数包装器:
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 次,并将获得获取类型 "E" 参数的仿函数,最后使用参数 "A":
调用内部处理程序
auto inner_handler = [] (A) -> bool { return false; };
auto f = foo (foo (foo (foo ( inner_handler ))));
f (E {});
我想要的是实现 call_until 函数,该函数会递归地调用 "foo" 重载,直到结果仿函数的参数类型变为 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);
}
但是我遇到了编译错误并且有点卡在了这一点上。我需要一些想法来实现这个。
您的直接问题是 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);
}
};
这是一个使用了上面helper的函数,所以我们只需要传入一个类型(test),其余推导:
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
右值调用的类型的测试:
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{};
我们完成了。语法不同,但这只是一些整理工作。
我有一些自定义类型将用作函数的不同参数:
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
还有一些函数是 returns 仿函数包装器:
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 次,并将获得获取类型 "E" 参数的仿函数,最后使用参数 "A":
调用内部处理程序auto inner_handler = [] (A) -> bool { return false; };
auto f = foo (foo (foo (foo ( inner_handler ))));
f (E {});
我想要的是实现 call_until 函数,该函数会递归地调用 "foo" 重载,直到结果仿函数的参数类型变为 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);
}
但是我遇到了编译错误并且有点卡在了这一点上。我需要一些想法来实现这个。
您的直接问题是 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);
}
};
这是一个使用了上面helper的函数,所以我们只需要传入一个类型(test),其余推导:
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
右值调用的类型的测试:
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{};
我们完成了。语法不同,但这只是一些整理工作。