2016-08-01 31 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 

這是基本的編譯時間組成。如果你想要運行時組合,事情會變得更加複雜。