2016-08-01 276 views
0

我是C++的初学者,想做一个复合函数的简单例子。 例如,在MATLAB,我可以写C++中的复合函数

a = @(x) 2*x 
b = @(y) 3*y 
a(b(1)) 

答案是6

我搜索了以下问题。 function composition in C++/C++11Function Composition in C++

但它们均采用了先进的功能,如模板,对此我不会在这个时候很多熟悉的创建。有没有一种简单而直接的方法来实现这一目标?在上面的MATLAB代码中,用户不需要知道函数句柄的实现。用户可以使用正确的语法来获得结果。 C++中有这样的方法吗?

**另一个编辑:**

在上面的代码中,我把一个值在末端。但是,如果我想将结果传递给第三个函数,MATLAB仍然可以将其视为函数。但是,如何在C++中做到这一点?

例如,除了上面的代码,考虑下面的代码:

c = @(p,q) a(p)* b(q) %This results a function 
c(1,2) 
answer=12 

d = @(r) a(b(r)) 
d(1) 
answer=6 

function [ output1 ] = f1(arg1) 
val = 2.0; 
output1 = feval(arg1,val) 
end 

f1(d) 
answer = 12 

在此代码,c需要两个函数作为输入和d是复合函数。在下一个示例中,函数f1以函数作为参数,并使用MATLAB内建函数feval来评估函数val

我该如何在C++中实现这一点?

+3

可能类似于[C++ lambda函数](http://en.cppreference.com/w/cpp/language/lambda)? '@(x)'在MATLAB中究竟做了什么? –

+0

我还是不明白'fun1'。它看起来像一个参数'c',忽略了这个参数,并且无条件地*返回*'a'。然后,你*调用*'fun1',传递'1',这应该被忽略,但不知怎的,你得到的答案是2,而不是'@(x)2 * x'或'a'。 WTF? – zwol

+0

函数组合是一个接受两个函数并返回另一个函数的操作。我没有在matlab代码中看到任何函数组合,你能告诉我它隐藏的位置吗? –

回答

4

也许我误解你的问题,但它听起来很简单:

int a(const int x) { return x * 2; } 
int b(const int y) { return y * 3; } 

std::cout << a(b(1)) << std::endl; 

关于你的最新的编辑,你可以做一个函数返回另一个函数的结果:

int fun1(const int c) { return a(c); } 

std::cout << fun1(1) << std::endl; 

注意这返回一个数字,结果调用a,而不是功能a本身。当然,您可以将指针返回给该函数,但是其语法会有所不同:您必须编写诸如之类的内容,这相当难看且复杂。

+0

这不会编译。 –

+0

@ForceBru感谢您的回答。我编辑了问题。你可以看一下吗? – 34usdh34

2

C++的evaluation strategy为函数参数是总是 “由值” “急切” 和通常。什么意思简短的版本是,一个由函数调用序列,如

x = a(b(c(1))); 

完全一样

{ 
    auto t0 = c(1); 
    auto t1 = b(t0); 
    x = a(t1); 
} 

auto t0的意思是“给t0任何类型是最合适的”;它是一个相对较新的功能,可能无法在C++编译器中使用。大括号表示临时变量t0t1在分配给x后被销毁。)

我提出这个问题是因为你一直在讨论函数“以函数作为输入”。有编程语言,如R,其中写a(b(1))会通过表达b(1)a,只有真正呼叫ba要求表达进行评估。我想 MATLAB不是那样的,但我可能是错的。无论如何,C++肯定是而不是那样。在C++中,a(b(1))首先评估b(1),然后将该评估的结果传递给a; a无法找出结果来自b的电话。只有在C++中正确描述为“以另一个函数作为输入的函数”的情况将对应于您使用feval的示例。

现在:你已经证明了MATLAB代码的最直接的翻译是

#include <stdio.h> 

static double a(double x)   { return 2*x; } 
static double b(double y)   { return 3*y; } 
static double c(double p, double q) { return a(p) * b(q); } 
static double d(double r)   { return a(b(r)); } 

static double f1(double (*arg1)(double)) 
{ return arg1(2.0); } 

int main() 
{ 
    printf("%g\n", a(b(1))); // prints 6 
    printf("%g\n", c(1,2)); // prints 12 
    printf("%g\n", d(1));  // prints 6 
    printf("%g\n", f1(d)); // prints 12 
    printf("%g\n", f1(a)); // prints 4 
    return 0; 
} 

(C++已经不需要像feval明确的语法,因为输入的参数声明,double (*arg1)(double)告诉编译器arg1(2.0)是有效的。在旧的代码,你可能会看到(*arg1)(2.0)但是这不是必需的,我认为它使代码的可读性。)

(我在此代码中使用printf,而不是C++的输入输出流,部分原因是因为我个人认为printf是比iostreams更符合人体工程学,部分原因是这使得这个程序也是一个有效的C程序具有相同的语义。例如,如果你学习C++的原因是因为你想编写MATLAB扩展,那么,如果你坚持使用普通的C,最后一次检查的实际上更容易。)

有显着性差异;例如,MATLAB函数接受向量,而这些C++函数只取单值;如果我希望b致电c,我将不得不将它们交换或在b以上写上c的“前向声明”;和C++中(除了一些你现在不需要担心的例外),你所有的代码都必须在一个或另一个函数中。学习这些差异是学习C++的一部分,但是您不需要将自己与模板,lambda表达式和类等混淆在一起。首先坚持使用固定类型签名的免费功能。

最后,如果我没有提到,在

static double c(double p, double q) { return a(p) * b(q); } 

ab呼叫可能在任意顺序发生,我将是失职。有谈到改变这一点,但还没有发生。

+0

'std :: printf'?真?!?即使是OP使用'std :: cout'。 –

+0

@NikBougalis我相信我对iostreams的看法很清楚;-) – zwol

+0

感谢您的回答。我编辑了问题。你可以看一下吗? – 34usdh34

4

如何:

#include <iostream> 

int main(int, char**) 
{ 
    auto a = [](int x) { return 2 * x; }; 
    auto b = [](int y) { return 3 * y; }; 

    for (int i = 0; i < 5; ++i) 
     std::cout << i << " -> " << a(b(i)) << std::endl; 

    return 0; 
} 
+0

这就是我的想法。看起来和这个MATLAB代码最相似,并且是内联的。 –

+0

感谢您的回答。我编辑了问题。你可以看一下吗? – 34usdh34

+0

您可以根据需要创建任意数量的lambda,并链接它们。 –

0
int a(const int x){return x * 2;} 
int b(const int x){return x * 3;} 
int fun1(const int x){return a(x);} 

std::cout << fun1(1) << std::endl; //returns 2 

这是基本的编译时间组成。如果你想要运行时组合,事情会变得更加复杂。