3

For each argument I need apply two nested function:

obj.apply(someFilter(arg)); // arg is one argument, but here
                            // should be an unpacking of args

I don't know how to write unpacking for such case.

I saw this:

 pass{([&]{ std::cout << args << std::endl; }(), 1)...};

on wiki, but again don't know how to apply this for my case.

user14416
  • 2,922
  • 5
  • 40
  • 67
  • When you say unpacking, do you mean that your single argument 'arg' should be unpacked into multiple arguments? – souldzin Mar 07 '13 at 16:53

3 Answers3

4

It's actually quite simple: You can put arbitrary expression inside the unpack of an variadic templates argument pack:

obj.apply(someFilter(arg))...

This will give you the result of obj.apply as a coma seperated list. You can then pass it to a dummy function:

template<typename... Args> swallow (Args&&...) {}
swallow(obj.apply(someFilter(arg))...);

To swallow the comma seperated list.

Of course, this assumes that obj.apply returns some kind of object. If not you can use

swallow((obj.apply(someFilter(arg)), 0)...);

to make actual (non void) arguments

If you don't know what obj.apply` returns (result might have overloaded the comma operator), you can disable the use of custom comma operators by using

swallow((obj.apply(someFilter(arg)), void(),  0)...);

Should you actually need to evaluate the items in order (which doesn't seem very likely from the question), you can abuse array initialization syntax instead of using a function call:

using Alias=char[];
Alias{ (apply(someFilter(args)), void(), '\0')... };
Grizzly
  • 19,595
  • 4
  • 60
  • 78
  • Error - expression contains unexpanded parameter pack 'args' Error - expected ';' after expression – user14416 Mar 07 '13 at 16:57
  • @user14416: Does it still give that error with my edit? I accidently posted the answer before it was finished. – Grizzly Mar 07 '13 at 16:59
  • Note that the above requires that `obj.apply` returns non-void, and evaluates the arguments in an unspecified order. – Yakk - Adam Nevraumont Mar 07 '13 at 17:03
  • @Yakk: No it doesn't (require a non-void). I was editing while you wrote the comment – Grizzly Mar 07 '13 at 17:05
  • Ok, now if `obj.apply` returns an object with an overrided `operator,`, the above results in unexpected behavior. – Yakk - Adam Nevraumont Mar 07 '13 at 17:11
  • @Yakk: Which is why I said if it returns `void`, since I didn't want to go into putting a `void()` in, but ok, why not. – Grizzly Mar 07 '13 at 17:13
  • Thank you for demonstrating `using Alias=char[]; Alias{ (apply(someFilter(args)), void(), '\0')... }`, is why I don't recommend this strategy for running code with unpacking of parameter packs. It works, but it is about as far away from self documenting as you can imagine. And if you don't reach that mess, you end up with something fragile. C++ has a language feature for packaging up code snippets -- lambdas. I recommend using them instead of this hack. – Yakk - Adam Nevraumont Mar 07 '13 at 18:29
1

Here is a robust way to do an arbitrary set of actions on a parameter pack. It follows the principle of least surprise, and does the operations in order:

template<typename Lambda, typename Lambdas>
void do_in_order( Lambda&& lambda, Lambdas&& lambdas )
{
  std::forward<Lambda>(lambda)();
  do_in_order( std::forward<Lambdas>(lambdas)... );
}

void do_in_order() {}

template<typename Args>
void test( Args&& args ) {
  do_in_order( [&](){obj.apply(someFilter(std::forward<Args>(args)));}... );
}

Basically, you send a pile of lambdas at do_in_order, which evaluates them front to back.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

I assume that the code has multiple args as a parameter pack? Try:

obj.apply( someFilter( arg )... );

as parameter unpacking applies to the expression, so each element of the parameter pack get's expanded into someFilter( arg ).

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180