约束模板参数取决于传递的仿函数

时间:2017-12-22 21:52:57

标签: c++ c++11 templates lambda

我想根据传递的仿函数约束模板参数。从某种容器类型中考虑这个FoldLeft函数:

template<typename F, typename R>
R FoldLeft(F&& functor, R initialValue) {
    R r = initialValue;
    /* assume that this is a range of uint64_t's */
    while (first != last) {
        r = std::forward<F>(functor)(r, *(first++));
    }
    return r;
}

可以像这样调用此函数:

auto sum = FoldLeft([](uint64_t i, auto& e) { return e + i; }, 0);

此处,问题是R是从initialValue参数中推导出来的,在这种情况下为0,因此导致int。同样,decltype(sum)也会提供int

我希望将R推导为函子的返回类型,可以是lambda或任何其他可调用类型。我已经尝试使用this answer中的方法,但总是遇到这个错误:

error:  decltype cannot resolve address of overloaded function
struct function_traits
       ^~~~~~~~~~~~~~~
note:   substitution of deduced template arguments resulted in errors seen above

我的尝试代码(fuction_traits从链接的答案中复制):

template<typename T>
using LamRet = typename function_traits<T>::result_type;

template<typename F>
LamRet<F> FoldLeft(F&& functor, LamRet<F> initialValue) {
    LamRet<F> r = initialValue;
    /* assume that this is a range of uint64_t's */
    while (first != last) {
        r = std::forward<F>(functor)(r, *(first++));
    }
    return r;
}

1 个答案:

答案 0 :(得分:3)

函数特性几乎没用,并且使用它们会像这样绑定,因为C ++中的callable没有像函数特征那样的特性。

只有一部分可调用的人只有这样的特征。你编写的C ++ 14和C ++ 17风格的lambda越多,calgbles就越少。

确定返回值,您需要知道迭代的类型是什么。然后检查decltype( lambda( argument, iterated_type ) )(也可以写为result_of_tinvoke_result_t模板类型。)

假设您的迭代类型为T,您的参数为A

template<class F, class A>
using LamRet = std::decay_t<std::result_of_t<F&&( A&&, T& )>>;

然后我们可以用:

检查我们的lambda参数类型
template<class F, class A>
using LamArgGood = std::is_convertible< A&&, LamRet<F, A> >;

template<class F, class A>
using LamRetGood = std::is_convertible< LamRet<F, A>, LamRet< F, LamRet<F, A > >;

确保迭代的返回类型有效。

template<class F, class A,
  class dA = std::decay_t<A>,
  std::enable_if_t< LamArgGood<F, dA>{} && LamRetGood<F, dA>{}, bool> =true
>
LamRet<F, dA> FoldLeft(F&& functor, A&& initialValue) {
  LamRet<F, dA> r = std::forward<A>(initialValue);
  /* assume that this is a range of uint64_t's */
  while (first != last) {
    r = std::forward<F>(functor)(r, *(first++));
  }
  return r;
}

这不太对,但会捕获99%的类型错误。 (我在迭代中分配,而不是构造;我从A&&转换为LamRet,而不是dA&&。)