[英]How to define the function composition in c++17?
我想計算函數組成-f(g(param))。 這是我嘗試過的:
auto fComposition(auto&& f, auto&& g, auto&&... params)
{
/* some stuff */
auto result = std::forward<decltype(f)>(f)(
std::forward<decltype(g)>(g)(
std::forward<decltype(params)>(param)
)
);
/* other stuff */
return result;
};
編譯
g++ -std=c++17 src.cpp
基本測試
#include <random>
#include <math.h>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> distr(-1.0, 1.0);
auto xx = fComposition(round, distr, gen);
return 0;
}
我得到的消息是它不能識別第一個函數的類型。
順便說一句,這真的是您的代碼嗎? 您沒有在擴展params
因此它不應編譯。
I.定義構圖的方式與簡單的調用沒有區別:您的fComposition(f, g, arg)
與f(g(arg))
相同,除了鍵入額外的字符外。 真正的組合通常是一個接受兩個函數並返回一個閉包的組合器,當對實際參數調用該閉包時,它們會連續應用它們。 就像是:
template<class F, class G> auto comp(F f, G g) {
return [f, g](auto &&... args) {
return f(g(std::forward<decltype(args)>(args)...));
};
}
(請注意按值綁定。在C ++ 17中,它們比二十年前還先進。:)您可以按口味添加std::move
和std::forward
。)
這樣,您可以組成兩個功能:
auto fg = comp(f, g);
然后在參數上調用結果:
auto x = fg(arg1, arg2);
二。 但是實際上,為什么限制自己有兩個操作數? 在Haskell中, (.)
是單個二進制函數。 在C ++中,我們可以有一整個重載樹:
template<class Root, class... Branches> auto comp(Root &&root, Branches &&... branches) {
return [root, branches...](auto &&...args) {
return root(branches(std::forward<decltype(args)>(args)...)...);
};
}
現在,您可以將任何AST封裝在一個可調用的容器中:
int f(int x, int y) { return x + y; }
int g(int x) { return x * 19; }
int h(int x) { return x + 2; }
#include <iostream>
int main() {
auto fgh = comp(f, g, h);
std::cout << fgh(2) << '\n';
}
我知道,類似的技術是在11標准之前的C ++中具有匿名閉包的唯一方法。
三, 但是,等等,有圖書館解決方案嗎? 實際上,是的。 來自std::bind
的描述
如果存儲的參數arg是
std::is_bind_expression<T>::value == true
類型(例如,另一個綁定表達式直接傳遞到綁定的初始調用中),則bind執行函數組合:傳遞bind子表達式將返回的函數對象,該子表達式將被急切地調用,並將其返回值傳遞給外部可調用對象。 如果bind子表達式具有任何占位符參數,則它們與外部綁定共享(從u1, u2, ...
挑選)。 具體而言,上述std::invoke
調用中的參數vn
為arg(std::forward<Uj>(uj)...)
,而同一調用中的類型Vn
為std::result_of_t<T cv &(Uj&&...)>&&
(cv資格與g相同)。
抱歉,目前沒有示例。 > _ <
PS並且是的, std::round
是一個重載函數,因此您應該進行類型轉換以指定需要組成的重載。
random
包含的包含cmath
,它在libstdc++
還定義了默認名稱空間以及std
名稱空間中的幾個數學運算符(包括round
)。 (有關基本原理,請參見此答案 。)C ++的round
具有多個重載。 結果,您有多個可用的round
版本,並且您的函數不知道您要使用哪個round
,因此會出現有關歧義的錯誤消息。 正確的解決辦法是消除歧義這round
你的意思。 您可以使用靜態強制轉換執行此操作:
static_cast<double(*)(double)>(round)
由於無論如何都必須解決問題,因此您也可以使用cmath
標頭代替math.h
並使用std::round
。 至少那時您知道它會在前面超負荷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.