簡體   English   中英

如何在C ++ 17中定義函數組成?

[英]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::movestd::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調用中的參數vnarg(std::forward<Uj>(uj)...) ,而同一調用中的類型Vnstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM