为只接受函数的函数定义接口

Defining interfaces for functions that only accept functions

本文关键字:函数 接口 定义      更新时间:2023-10-16

定义(f+g(为平均值(f+g((x(:=f(x(+g(x(。传统的矩阵加法与这个定义是一致的。

以下是一个简单的实现

template<typename Funcf, typename Funcg>
auto operator+(Funcf f, Funcg g){
  return [f, g](auto x){return f(x) + g(x);};
}

由于operator+只使用用户定义的类型,因此此操作失败。下一次尝试给出

template<typename R, typename I>
auto operator+(std::function<R(I)> f, std::function<R(I)> g){
  return [f, g](auto x){return f(x) + g(x);};
}

这是有效的,并且不会破坏命名空间。然而,它丢弃了间接性,并且调用站点是丑陋的auto added = std::function<int(int)>{f} + std::function<int(int)>{g};

如果第一个operator+被允许(或者被重命名以添加(,那么调用站点会更好,并且函数会内联。但它试图与一切相匹配,这似乎很脆弱。

是否可以定义一个模板接口,指定输入是函数,仍然内联它们,但不会用过于通用的名称污染命名空间?

换句话说,有没有std::function的编译时版本具有更方便的调用站点?我强烈怀疑答案是否定的。如果答案是否定,那么上述两个极端之间是否存在妥协?

或者选项三,我是不是想错了?您将如何在c++中建模(f+g(?

运算符仅适用于用户定义的类型。那么让我们让你的功能成为!

我们可以定义一个基本上是lambda的类型,但使用用户定义的类型名称:

template<typename F>
struct addable_lambda_impl : F {
    template<typename T>
    addable_lambda_impl(T f) : F{std::move(f)} {}
    using F::operator();
};
template<typename F>
addable_lambda_impl<F> addable_lambda(F f) {
    return addable_lambda_impl<F>{std::move(f)};
}

这是一个将扩展任何类型并使用其operator()函数的类。

现在,您可以使用addable_lambda功能:

auto lambda = addable_lambda([](){});

实现您的运营商也更容易:

template<typename F, typename G>
auto operator+(addable_lambda_impl<F> f, addable_lambda_impl<G> g){
  return addable_lambda([f, g](auto x){ return f(x) + g(x); });
}

它并不完美,但稍微不那么丑陋。此外,您不会遭受std::function添加的开销。