2017-04-05 29 views
0

我想要寫代表的這些產物(在數學意義上)一個函數,它接受的形式float(float, float)的功能的任意數量的,併產生一個可調用對象(例如,lambda表達式)功能。產品的功能與一個倍表達

我們能做到這一點,例如,以下列方式:

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

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

+5

折表達式是C++只是17。你在問如何替換fold表達式並在C++ 14中具有'constexpr''? –

+3

此外你可能想'[=]','不[b]'... – Barry

+0

@VittorioRomeo不,我想噸至保持倍的表達,但實現的C++ 14的感'constexpr'ness。 – 0xbadf00d

回答

1

如果你真的想彎腰向後使用倍的表達,你仍然可以做到這一點。您將需要一個輔助功能類:

#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); 
} 

的想法是幾乎完全一樣維托裏奧的,除非我們使用了std::tuple這樣我們就可以對於類型爲final的函數對象以及相同類型的多個函數,使用product_of函數。

std::index_sequence被用於重新獲得一個參數包只是讓我們可以做倍的表達。


只需轉換維托裏奧的解決方案工作,以及,但與告誡我提到(均未的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)); 
    } 
}; 
2

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


只要記住,lambda表達式只是語法糖函數對象與超載operator()

下面是一個使用initializer_list爲可變參數膨脹C++ 14溶液。

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); 
} 

live example on wandbox

+0

我的編譯器是Visual Studio 2017附帶的編譯器。與許多其他編譯器一樣,MSVC至今只支持C++ 17。所以,正如我在這個問題中寫的,我想保留fold表達式,但是在C++ 14的意義上實現'constexpr'(因爲MSVC不支持'constexpr' lambdas)。 – 0xbadf00d

+2

@ 0xbadf00d我不明白對摺疊表達式的癡迷,你想向後彎曲來做它。 – Justin

+0

@Vittorio你爲什麼從函數中派生出來?爲什麼不使用'std :: tuple'?這對我來說只是一個缺陷 - 你不能擁有最終的函數對象,而且你不能兩次使用同一個函數類。 – Justin