如何将函数的y→λx.yx'提升'转换为仿函数?

时间:2016-01-24 21:15:37

标签: c++ c++11 functor lambda-calculus idiomatic

编辑:一个单线摘要:是否可以创建一个模板化类型,其operator()调用任意函数,指定为模板参数?

考虑(模板化)函数

template <typename T> std::operator-(const T& lhs, const T& rhs)

在标准C ++库中,<functional>我们have以下构造(忽略constexpr和C ++ 14中的默认void,以及binary_function的便利继承): / p>

  template<typename T>
  struct minus {
      T operator()(const T& lhs, const T& rhs) const {
          return operator-(lhs, rhs) 
      };
  };

所以,'functor'(用标准库说法)std::minus是一种“提升”函数operator-。我们同样拥有std::plusstd::multiplies等等。

现在,假设我想为任意函数实现同样的效果。这是我用宏来做的(对于已知数量的参数,例如2)

#define CONCAT(s1,s2) s1##s2
#define EXPAND_THEN_CONCAT(s1,s2) CONCAT(s1,s2)
#define DEFINE_FUNCTOR(f, ret_type, param1_type, param2_type) \
    struct EXPAND_THEN_CONCAT(f,_functor)  { \
        ret_type operator()(param1_type x, param2_type y) const { \
            return f(x, y)  \
        }; \
    };

...但当然我想用C ++ 11方式(或C ++ 14方式,如果有帮助)。我该怎么办?

我有想法以某种方式将f in作为模板参数传递;但是如何让operator()与f具有相同的签名(并使用const标记)?对于一个固定的签名,我认为它不会那么困难,而且代码应该看起来像std::minus - 但总的来说我无法真正看到它将如何完成。

我曾想过尝试类似于我在函数的“提升调用”中使用的东西:

template<typename F, typename... Parameters>
inline void invoke(const F& f, Parameters... parameters) {
    f(parameters...);
}

但是,再次,这不会削减它 - 这将让我得到我喜欢的执行,但不是我喜欢的签名;我需要那个签名......

2 个答案:

答案 0 :(得分:4)

std::minus类型。它是一个具有operator()重载的类型,恰好在它给出的参数上调用operator-

您是否在询问是否有办法创建可以调用任意函数的类型?这将要求您以某种方式指定调用该类型的函数。向类型提供参数的唯一方法是通过模板参数。

虽然non-type template parameters可能是函数指针,但它们不会像std::minus那样工作,operator-通过重载解析等调用#define CREATE_FUNCTOR(f) \ [=](auto&& ...args) -> decltype(auto) \ { \ return f(std::forward<decltype(args)>(args)...); \ } 。函数指针指向特定函数,而不是重载集。

您似乎想要的是能够指定一个标识符,并获取一个对象,该对象在被调用时将完全调用该标识符,就像您直接调用它一样。这包括重载决议等。

C ++作为一种语言不能做到这一点。论文P0119 (PDF)是添加此类语言功能的提案,但它不处理成员函数。目前还不清楚Kona在2015年的情况如何,如果它出现的话。

你能得到的最接近的是通过C ++ 14 lambdas改进你的宏:

this

这里使用lambda的原因是,如果你在一个成员函数中使用它,如果f碰巧是一个成员函数,lambda将能够捕获myprj/templates/index.html <h1>${_('Home')}</h1> 。它也将被视为封闭类型的朋友。

当然,这会创建一个值,而不是一个类型。

答案 1 :(得分:1)

这是你想要的吗?

#include <iostream>
#include <utility>

template <typename Sig, Sig& f>
struct func_wrapper;

template <typename R, typename... Args, R(&f)(Args...)>
struct func_wrapper<R(Args...), f> {
  template <typename... Ts>
  R operator ()(Ts&&... xs) const {
    return f(std::forward<Ts>(xs)...);
  }  
};

int func(int x) {
  return x;
}

int main() {
  func_wrapper<decltype(func), func> f;
  std::cout << f(1) << std::endl;
}