0

I have a function2, which can be called with or without a second argument == char. If so, I want to modify that char-Argument.

Given

void function1_caller(int x) { 
    char ws=7; 
    function2_modifyArg(x, ws); 
}

This works:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, ws ...);
}

simply put in parenthesis, doesn't work already:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, (ws ... )); 
}

This results in the following error:

Syntax error: unexpected token '...', expected declaration

In fact here I'd like to modify the argument, but of course I get the same

Syntax error: unexpected token '...', expected declaration
template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, (ws ... / 3));
}

template <typename ... WS> 
void function3_end(int x, WS ... ws) {};
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
GGeorge
  • 3
  • 2
  • 2
    I'm not entirely sure what you mean, but to modify arguments they have to be references. Could you show an input/output example of what this function should do? – cigien Oct 02 '21 at 04:43
  • If all you need is a second argument, an overload seems better suited. No template required to have a function that has one or two parameters. I could be missing the actual point though. – chris Oct 02 '21 at 04:51
  • Thx chris for the highlighting and cigien for the comment, which I dont understand yet complety :) Within a normal function call like in function1_caller(x, ws/3) I can simply "modify" the argument (divide it by 3). Yet, with the eventually given Parameter Pack argument, I cant to it so directly like if it was a normal char argument. The syntax is a kinda weird. Usually putting things into braces doesn't change anything, but putting braces around the parameter pack (ws ... ) like in function2_modifyArg-Version#2 gives error The eventual p-pack is just an additional char – GGeorge Oct 02 '21 at 05:22
  • @chris: is just about code length: the function-bodies are longer compared to the 1 line, where the 2nd argument is grabbed up. Thx though >) – GGeorge Oct 02 '21 at 05:27
  • I thought the parameter "pack" is just handled like a char by the compiler: "aha, this call of the function is with argument 2 (== char), so I can devide/"modify" it" – GGeorge Oct 02 '21 at 05:33
  • TBH, this sounds like a XY-problem. Have you considered a different simpler solution, like overloading? You are not giving enough details, i.e. it is difficult to understand that the underlying problem is that you want to solve. You've made it too abstract and are asking us to fix your solution to this. And e.g. _"If so, I want to modify that char-Argument."_ ..*How* do you want to modify it? I.e. state the underlying problem please. – JHBonarius Oct 02 '21 at 06:30

2 Answers2

2

ws... expands to a comma-separated list of the values in ws, but only in specific contexts, not anywhere such a list could produce valid syntax. One such context is as a series of function arguments as in function3_end(x, ws ...).

Both (ws...) and (ws... / 3) aren't allowed. If this were simply a note to the compiler to "Hey, expand this out and then try to compile it", both would actually compile for non-empty packs, but the first would be a series of comma operators and the second would have the last value divided by 3. Neither is particularly as helpful as a compiler error. The first can even be done explicitly using a fold expression, e.g., (..., ws).

What you can do is pick one of those valid contexts and apply a pattern to each element of the pack:

function3_end(x, (ws/3)...);

This copies the pattern while expanding and works fairly intuitively once you see some expamples. The ellipsis applies to the "group" of syntax to its left, which is (ws/3) in this case, leading to an expansion of (ws₀/3), (ws₁/3), (ws₂/3), …. In the single-element case, this is equivalent to (ws₀/3), and with no elements, the entire pattern is "copied" 0 times, which is exactly what you want. Parentheses are not mandatory for this simple pattern, but I would recommend them in general to make the expansion scoping perfectly clear.


Now all that said, I would rather avoid the template and use an overload:

void function3_end(int x);
void function3_end(int x, char ws);

Detection is easy—one body is for the second argument and one is for without. This also signals that the second argument is a char, not any type that may or may not have some extra constraint added on top to make it a char in disguise. The variadic template doesn't even signal that this function can't be called with more than 2 arguments. In addition, these overloads can be split from their declaration and placed into a separately compiled source file, as well as preventing extra template instantiations. Finally, if this would violate DRY, you can factor the common parts into separate functions that are used within both overloads.

chris
  • 60,560
  • 13
  • 143
  • 205
  • Ha, thx, perfect. :) Now I don't know whom to give the 'green arrow' ;) ! chris, do you still know wether one can indicate the compiler that the parameter pack type is in fact one 'char' ? (like "template " instead of "template " ) – GGeorge Oct 02 '21 at 06:52
  • @GGeorge, You can technically constrain it, e.g., `requires (sizeof...(WS) == 1 and std::convertible_to...)`, but that's about the best it gets and it looks pretty outlandish for a reason. You could always use a `std::optional` parameter too if you need to detect the presence or absence of the argument as opposed to a default value. And don't worry about needing to choose one answer to accept, the other will still be right here. – chris Oct 02 '21 at 07:00
  • using `std::optional` now :), works a perfectly https://devblogs.microsoft.com/cppblog/stdoptional-how-when-and-why/ don't try to contact a microsoft guy / unavailable.. – GGeorge Oct 04 '21 at 21:44
0

You don't need the parenthesis you just need to put the operation you want to do before the pack expansion:

template <typename ... WS> 
void function2_modifyArg(int x, WS ... ws) { 
    function3_end(x, ws / 3 ...);
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60