分发参数参数包以调用两个仿函数

时间:2015-12-07 16:35:20

标签: c++ templates c++14

我尝试通过一个给定的参数包($this->db->query("UPDATE forum_posts set like = like + 1 where post_id = $post_id"); )调用两个函数对象,提供一个整数参数来标记我需要拆分包以正确调用两个功能对象的边框。

考虑以下示例:

typename Args... args

我的想法是创建两个整数序列并使用Args... = <int, int, std::vector<int>, std::vector<int>> unsigned Bounds = 2; functor Foo (left) and Bar (right) // Foo is invoked with <int, int> // Bar is invoked with <std::vector<int>, std::vector<int>> // An evaluator template class is invoked to merge the result of both, // for example with an add (operator+) operation 同时使用这两个整数序列调用两个函数对象:

std::get

然而,VisualStudio 14编译器抱怨参数包中的参数计数与序列中的参数计数不匹配:

  

错误C3528:&#39; LeftSeq&#39;:此包扩展中的元素数量与&#39; args&#39;

中的元素数量不匹配

仍然有办法将// Sequence creator template<unsigned Position, unsigned Count, unsigned... Pack> struct make_sequence : std::conditional< Count == 0, std::common_type<sequence<Pack...>>, make_sequence<Position + 1, Count - 1, Pack..., Position> >::type { }; // Create a sequence from inclusive from to exclusive to template<unsigned InclusiveFrom, unsigned ExclusiveTo> using make_sequence_from_to_t = typename make_sequence< InclusiveFrom, (ExclusiveTo <= InclusiveFrom) ? 0U : (ExclusiveTo - InclusiveFrom) >::type; template<typename LeftType, typename RightType, unsigned Bounds, typename Evaluator> class distribute_functor { LeftType left_; RightType right_; template<unsigned... LeftSeq, unsigned... RightSeq, typename... Args> auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>, Args... args) { return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...), // ~~~~~~~~~~~~~~~^^^^^^^~~^^^^~~~~~ // error C3528: 'LeftSeq': the number of // elements in this pack expansion does not // match the number of elements in 'args' right_(std::get<RightSeq>(args)...)); } public: template<typename Left, typename Right> distribute_functor(Left left, Right right) : left_(std::forward<Left>(left)), right_(std::forward<Right>(right)) { } template<typename... Args> auto operator() (Args... args) { return internal_invoke(make_sequence_from_to_t<0, Bounds>{}, make_sequence_from_to_t<Bounds, sizeof...(Args)>{}, std::forward<Args>(args)...); } }; 用于我不喜欢的仿函数调用。

是否有另一种或更好的方法可以在一个步骤中从一个参数包中部分调用两个功能对象?

1 个答案:

答案 0 :(得分:3)

sub reduce_1level { my $cds = shift; if (ref $cds eq 'ARRAY') { foreach (@$cds) { reduce_1level ($_) if ref; } } elsif (ref $cds eq 'HASH') { foreach my $key (keys %$cds) { if (ref $cds->{$key} eq 'ARRAY' and @{$cds->{$key}} == 1) { $cds->{$key} = $cds->{$key}[0]; } next unless ref $cds->{$key}; reduce_1level ($cds->{$key}); } } } 不能以这种方式使用。

你应该像这样写std::get

internal_invoke

并使用template<unsigned... LeftSeq, unsigned... RightSeq, typename ArgsAsTuple> auto internal_invoke(sequence<LeftSeq...>, sequence<RightSeq...>,ArgsAsTuple&& args) const { return Evaluator::evaluate(left_(std::get<LeftSeq>(args)...), right_(std::get<RightSeq>(args)...)); }

调用它
forward_as_tuple

<强>解释

必须分别扩展两个不同arity的参数包。当你写return internal_invoke(make_sequence_from_to_t<0, Bounds>{}, make_sequence_from_to_t<Bounds, sizeof...(Args)>{}, std::forward_as_tuple(args...)); 时,你试图将不同的群体一起扩展。这是不可能做到的。你应该写std::get<LeftSeq>(args)...。这在语法上是正确的,但与std::get<LeftSeq>(args... /* 1st expand/) ... /* 2nd expand */ API不匹配。 std::forward_as_tuple可以帮助您,并且已经针对这些类型的用例进行了精确编写。

修改

如果您想避免元组,那么您必须编写自己的std::get版本以符合您的需要,前提是您按照我的说明正确扩展了参数。