Distribute argument parameter pack to invoke two functors

Denis Blank

I'm trying to invoke two functional objects through one given argument pack (typename Args... args), an integer parameter is provided to mark the border where i need to split the pack to invoke both functional objects correctly.

Consider the following example:

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

My idea was to create two integer sequences and use std::get to invoke both functional objects at once with those two integer sequences:

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

However the VisualStudio 14 compiler complains about a mismatch between the count of parameters in the arguments pack and in the sequence:

error C3528: 'LeftSeq': the number of elements in this pack expansion does not match the number of elements in 'args'

There is still the way to use std::tuple for the functor invocation which i don't prefer.

Is there another or better way to partial invoke two functional objects in one step from one argument pack?

Jean-Bernard Jansen

std::get cannot be used this way.

You should write internal_invoke like this:

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

And invoke it with forward_as_tuple:

return internal_invoke(make_sequence_from_to_t<0, Bounds>{},
                       make_sequence_from_to_t<Bounds, sizeof...(Args)>{},
                       std::forward_as_tuple(args...));

Explanation:

Two paramter packs of different arity must be expanded separately. When you write std::get<LeftSeq>(args)..., you try to expand together packs of different arity. This cannot be done. You should have wrote std::get<LeftSeq>(args... /* 1st expand/) ... /* 2nd expand */. This is syntactically correct but does not match std::get API. std::forward_as_tuple is there to help you and has been written precisely for those types of use cases.

Edit:

If you want to avoid the tuple, then you must write your own version of std::get to match your need, provided you expand the parameters correctly as I explained above.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Parameter pack with default template argument

From Dev

Extracting function argument types as a parameter pack

From Dev

Template deduction fails with argument after parameter pack

From Dev

C++ using a template parameter pack to invoke multiple templated functions

From Java

Why clang missing default argument on parameter pack error?

From Dev

Functors with two variables or more

From Dev

Does std::move invoke the copy operator if it's used as an argument on a && parameter?

From Dev

Invoke-Command : A positional parameter cannot be found that accepts argument

From Dev

Powershell Invoke-Command with PSCredential Cannot process argument transformation on parameter 'Credential'

From Dev

Parameter pack passed by reference

From Dev

Is it possible to typedef a parameter pack?

From Dev

Parameter pack expansion fails

From Dev

Tuple to parameter pack

From Dev

Expand a parameter pack with a counter

From Dev

Expanding container to parameter pack

From Dev

Behavior of a function parameter pack

From Dev

Using a range as a parameter pack

From Dev

Expand a parameter pack with a counter

From Dev

Expand parameter pack in order

From Dev

Permute the parameters in a parameter pack

From Dev

Parameter pack expansion questions

From Dev

std::min with Parameter Pack

From Dev

What does it mean to compose two Functors?

From Dev

Cannot invoke '_' with an argument list of type '_' - Which of the two choices should I use?

From Dev

Passing zero argument pack to printf

From Dev

Parameter count mismatch at Invoke

From Dev

Difference between typename parameter pack and auto parameter pack?

From Dev

Empty parameter pack expansion different to manual empty parameter pack

From Dev

C++ Convert a parameter pack of types to parameter pack of indices

Related Related

  1. 1

    Parameter pack with default template argument

  2. 2

    Extracting function argument types as a parameter pack

  3. 3

    Template deduction fails with argument after parameter pack

  4. 4

    C++ using a template parameter pack to invoke multiple templated functions

  5. 5

    Why clang missing default argument on parameter pack error?

  6. 6

    Functors with two variables or more

  7. 7

    Does std::move invoke the copy operator if it's used as an argument on a && parameter?

  8. 8

    Invoke-Command : A positional parameter cannot be found that accepts argument

  9. 9

    Powershell Invoke-Command with PSCredential Cannot process argument transformation on parameter 'Credential'

  10. 10

    Parameter pack passed by reference

  11. 11

    Is it possible to typedef a parameter pack?

  12. 12

    Parameter pack expansion fails

  13. 13

    Tuple to parameter pack

  14. 14

    Expand a parameter pack with a counter

  15. 15

    Expanding container to parameter pack

  16. 16

    Behavior of a function parameter pack

  17. 17

    Using a range as a parameter pack

  18. 18

    Expand a parameter pack with a counter

  19. 19

    Expand parameter pack in order

  20. 20

    Permute the parameters in a parameter pack

  21. 21

    Parameter pack expansion questions

  22. 22

    std::min with Parameter Pack

  23. 23

    What does it mean to compose two Functors?

  24. 24

    Cannot invoke '_' with an argument list of type '_' - Which of the two choices should I use?

  25. 25

    Passing zero argument pack to printf

  26. 26

    Parameter count mismatch at Invoke

  27. 27

    Difference between typename parameter pack and auto parameter pack?

  28. 28

    Empty parameter pack expansion different to manual empty parameter pack

  29. 29

    C++ Convert a parameter pack of types to parameter pack of indices

HotTag

Archive