簡體   English   中英

具有折疊表達式的函數的乘積

[英]Product of functions with a fold expression

我想編寫一個函數,它接受float(float, float)形式的任意數量的函數,並產生一個可調用對象(例如一個lambda表達式),它表示這些函數的乘積(在數學意義上)。

例如,我們可以通過以下方式執行此操作:

template<typename... BinaryFunctions>
auto product_of(BinaryFunctions... fs) {
    return [=](float x, float y) { return (... * fs(x, y)); };
}

但是,直到C ++ 17,即使fs是,返回的lambda也不是constexpr 所以,問題是:我想保留fold表達式,但是如何修改product_of使得返回的可調用對象是C ++ 14意義上的constexpr

如果可以使用fold表達式 ,則意味着您的編譯器支持C ++ 17。 如果您的編譯器支持C ++ 17,則lambda表達式在可能的情況下隱含constexpr 我假設你需要一個C ++ 14解決方案。


請記住, lambda表達式只是具有重載operator() 函數對象的語法糖。

這是一個C ++ 14解決方案,它使用initializer_list進行可變擴展。

template <typename... TFs>
struct product_of_fn : TFs...
{
    template <typename... TFFwds>
    constexpr product_of_fn(TFFwds&&... fs) : TFs(std::forward<TFFwds>(fs))... { }

    constexpr auto operator()(float x, float y)
    {
        std::initializer_list<float> results{static_cast<TFs&>(*this)(x, y)...};
        float acc = 1;
        for(auto x : results) acc *= x;
        return acc;
    }
};

用法:

template<int>
struct adder
{
    constexpr auto operator()(float x, float y){ return x + y; }
};

template<typename... TFs>
constexpr auto product_of(TFs&&... fs) {
    return product_of_fn<std::decay_t<TFs>...>(std::forward<TFs>(fs)...);
}

int main()
{
    auto f = product_of(adder<0>{}, adder<1>{});

    static_assert(f(1, 2) == 3 * 3);
}

wandbox上的實例

如果你真的想向后彎曲以使用折疊表達式,你仍然可以這樣做。 您將需要一個輔助功能類:

#include <tuple>
#include <utility>

template<typename... Fs>
class product_of_fn
{
    std::tuple<Fs...> fs;
public:
    template<typename... FsFwd>
    constexpr explicit product_of_fn(FsFwd &&... fs)
        : fs{ std::forward<FsFwd>(fs)... }
    {}

    constexpr auto operator()(float x, float y) {
        return impl(x, y, std::make_index_sequence<sizeof...(Fs)>{});
    }
private:
    template<std::size_t... Is>
    constexpr auto impl(float x, float y, std::index_sequence<Is...>) {
        return (... * std::get<Is>(fs)(x, y));
    }
};

用法(使用@VittorioRomeo的例子)

template<typename... Fs>
constexpr auto product_of(Fs... fs) {
    return product_of_fn<std::decay_t<Fs>...>{ std::forward<Fs>(fs)... };
}

template<int>
struct adder
{
    constexpr auto operator()(float x, float y) { return x + y; }
};

int main()
{
    auto f = product_of(adder<0>{}, adder<1>{});

    static_assert(f(1, 2) == 3 * 3);
}

這個想法和Vittorio幾乎完全一樣,除了我們使用std::tuple以便我們可以將product_of函數與類型為final函數對象以及相同類型的多個函數一起使用。

std::index_sequence用於重新獲取參數包,以便我們可以執行折疊表達式。


簡單地轉換Vittorio的解決方案也很有效,但是我提到的警告(沒有Fs可以是最終的或相同的):

#include <utility>

template<typename... Fs>
class product_of_fn : Fs...
{
public:
    template<typename... FsFwd>
    constexpr explicit product_of_fn(FsFwd &&... fs)
        : Fs{ std::forward<FsFwd>(fs) }...
    {}

    constexpr auto operator()(float x, float y) {
        return (... * static_cast<Fs &>(*this)(x, y));
    }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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