我想编写一个函数,它接受template<typename... BinaryFunctions>
auto product_of(BinaryFunctions... fs) {
return [=](float x, float y) { return (... * fs(x, y)); };
}
形式的任意数量的函数,并产生一个可调用的对象(例如一个lambda表达式),它代表这些函数的乘积(在数学意义上)。 / p>
我们可以通过以下方式执行此操作:
constexpr
但是,在C ++ 17之前,即使fs
为product_of
,返回的lambda也不是constexpr
。所以,问题是:我想保留fold表达式,但是如何修改{{1}}使得返回的可调用对象在C ++ 14意义上是{{1}}?
答案 0 :(得分: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);
}
答案 1 :(得分: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&#39}示例)
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
以便我们可以将product_of
函数用于类型为final
的函数对象,以及相同类型的多个功能。
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));
}
};