3

I want to expand a paramter pack into a function call, like this:

func(get_value(arg)...);

where func and get_value are two functions. The question is that get_value is sensitive to evaluation order, so I think one solution is to generate something like this:

func(get_value(arg0, 0), get_value(arg1, 1), get_value(arg2, 2));

if, for example, there're three parameters. With this counter I'll know the evaluation order. This there a way to do so?

Or as another solution, is there a way to simply specify the evaluation order of those calls to get_value with args? (If so, I don't even need a counter.)

Wu Zhenwei
  • 508
  • 3
  • 18
  • Do you mean you want the `get_value` calls to be evaluated strictly left to right, or is simply passing along 0, 1, 2... sufficient? – T.C. Aug 02 '14 at 03:51
  • @T.C. Exactly. That's what I want. – Wu Zhenwei Aug 02 '14 at 03:56
  • Which one? Left-to-right, or just passing the additional integer? – T.C. Aug 02 '14 at 03:57
  • Either. I can modify my get_value function to recieve an int if the first solution is impossible. – Wu Zhenwei Aug 02 '14 at 04:02
  • 1
    The way to make the order of evaluation strictly left-to-right would be to unpack the `get_value` calls inside a *braced-init-list* (e.g., store the results of the `get_value` calls into an array or a tuple, and then use the integer sequence trick). But g++ has a bug that breaks that, so it's currently more portable to go for the second approach. – T.C. Aug 02 '14 at 04:26
  • That bug is apparently [fixed](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253) in GCC 4.9.1, released a few days ago. – T.C. Aug 02 '14 at 04:44

1 Answers1

4

You can "zip" parameter packs together. So, something like this, using the definition of seq from here:

template <typename ... Args, int ... N>
void F(Args... args, seq<N...>)
{
func(get_value(args, N)...);
}

template <typename ... Args>
void FHelper(Args&&... args)
{
 F(std::forward<Args>(args)..., typename gens<sizeof...(Args)>::type ());
}

and you would call FHelper.

A simpler solution, in the case of get_value having a fixed return type would be to change func to take an initializer_list as input and call it like this :

func({get_value(args)...});

This preserves call order since the commas in the initializer-list are sequence points.

Community
  • 1
  • 1
Pradhan
  • 16,391
  • 3
  • 44
  • 59
  • @WuZhenwei I just added a simpler solution for a more restricted situation, just in case it applies to your problem. – Pradhan Aug 02 '14 at 04:12
  • 1
    "This preserves call order since the commas in the initializer-list are sequence points." Not quite. There's no sequence point in C++11. The list initialization rules guarantee strict left-to-right evaluation, but g++ is currently broken in that aspect. – T.C. Aug 02 '14 at 04:39
  • 1
    Hmm, looks like "currently" isn't quite right. It's apparently [fixed](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253) in GCC 4.9.1, released a few days ago. – T.C. Aug 02 '14 at 04:45