【问题标题】:Binding of regular function to std::function将常规函数绑定到 std::function
【发布时间】:2013-10-10 21:38:48
【问题描述】:

我正在尝试使用 C++ 中的运算符重载来编写函数式组合,以便拥有类似于函数式语言(例如 Haskell)中的简单组合语法。我的目标是在组合中使用常规的裸 C++ 函数。到目前为止,我编写了两个重载:

  1. operator% 使用两个 function<int(int)> 参数和
  2. operator* 使用模板类型作为参数。

operator% 运行良好,但在 main() 中,我首先必须将常规函数包装到 function<int(int)> 中,以便 operator% 接受它们作为输入参数。我想通过将它迁移到使用模板参数的重载operator* 来避免这个额外的步骤。我以为可以将正则函数绑定到operator*的模板参数上,但是编译器报错:

composingFunc.cpp11.cpp: In function ‘int main()’:
composingFunc.cpp11.cpp:28:12: error: invalid operands of types ‘int(int)’ and ‘int(int)’ to binary ‘operator*’
   cout<<(f*g)(5)<<endl;

你知道如何解决这个问题吗?在 operator* 中使用模板参数不是强制性的 - 如果您有其他方法,只需在此处提出建议。

这里是源代码:

#include<iostream>
#include<functional>

using namespace std;

int f(int n)
{  return 2*n; }

int g(int n)
{  return n+1; }

function<int(int)> operator%(function<int(int)> f, function<int(int)> g)
{ 
  return [=](int x){ return f(g(x));};
}

template<typename T>
function<int(int)> operator*(const T &f, const T &g)
{
  function<int(int)> f1=f,f2=g; //this is encapsulated here so it is not
                                //necessary to repeat the same in main 
                                //for every functional composition
  return [=](int x){ return f1(f2(x));};
}

int main()
{
  function<int(int)> f1=f, f2=g; //I want to encapsulate this step into operator*
  cout<<(f1%f2)(5)<<endl; //this works well
  cout<<(f*g)(5)<<endl; //error in this line
}

编辑: Zac 给出的解决方案使用类类型作为函数参数之一(根据标准,在运算符重载中必须使用至少一个枚举或类类型参数)和模板类型参数。然后常规 C++ 函数很乐意绑定到这两个参数。因此最终的运算符重载非常简单:

template<typename T>
function<int(int)> operator*(function<int(int)> f, T g)
{
    return [=](int x){ return f(g(x));};
}

然后可以使用简单的(f*g)(x) 语法组合常规函数。

【问题讨论】:

标签: c++ templates c++11 functional-programming operator-overloading


【解决方案1】:

想到的唯一想法是从一些假人开始:

struct F{}F;

function<int(int)> operator*(struct F, function<int(int)> g)
{
    return g;
}

function<int(int)> operator*(function<int(int)> f, function<int(int)> g)
{
    return [=](int x){ return f(g(x));};
}

int main()
{
    cout<<(F*f*g)(5)<<endl; // start with F, then add the real stuff
}

【讨论】:

  • 嗯,我不明白这将如何解决问题。此外,此解决方案无法编译: composingFunc.cpp11.cpp: In function 'int main()': composingFunc.cpp11.cpp:37:13: error: no match for 'operator*' (operand types are 'std::function' 和 'int(int)') coutfg)(5)
  • @RobinRobinovic 它确实编译了here。 (您也可以切换到 GCC4.8,这也可以)(但是是的,这不是一个真正的解决方案)。
  • 是的,它现在可以工作了 :) 我在您最近的编辑之前复制了代码 - 实际上那个代码编译得不好。因此,所需解决方案的问题是,至少一个参数必须是类(结构)或枚举类型,而常规函数不属于这些类型。我想知道初始帖子的问题是否可以用C++解决。
【解决方案2】:

正如 Daniel 指出的,运算符重载中的参数之一必须是类或枚举类型。因此对f*g 的调用需要实例化为function&lt;int(int)&gt; 而不是函数指针类型。这个问题有两种选择,

  1. 用函数代替运算符,如

    template<typename T>
    function<int(int)> multi(T x, T y)
    
  2. 将函数参数之一声明为`function

    template<typename T>
    function<int(int)> operator*(function<int(int)> x, T y)
    

【讨论】:

  • 谢谢扎克!第二个选项解决了问题!我已经开始失去希望了;)
  • @RobinRobinovic 这是如何工作的?对我来说肯定是does not work。你用什么编译器接受这个?另请注意,阅读此答案的第一句,调用本身的参数之一(不是重载运算符的声明)必须是类或枚举类型!
  • @Daniel Strange,它与 g++ v4.8.1 完美编译。在我家里的笔记本电脑上(甚至通过 cout g2=g;
  • @RobinRobinovic 昨天我在一个单独的问题中询问了difference between a+b and operator+(a,b),Dietmar 的回答对此进行了解释。为什么 GCC 4.8.1 会接受代码 (f*g) 对我来说仍然是一个谜,我确信它不符合标准,所以我不会依赖它!
  • @Zac 我仍然很困惑,为什么一个 std:function 参数的重载被接受但两个参数都不接受。
猜你喜欢
  • 2012-08-22
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多