2017-04-05 34 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