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

时间:2016-10-21 00:03:32

标签: c++ c++11

将(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)?

1 个答案:

答案 0 :(得分:1)

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

我们可以定义一个基本上是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添加的开销。