递归调用重载的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);
}

但是我遇到了编译错误并且有点卡在了这一点上。我需要一些想法来实现这个。

在线代码:http://ideone.com/ZRFxnw

您的直接问题是 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{};

我们完成了。语法不同,但这只是一些整理工作。

live example