I tried to write a function to check that a 'http::verb' is any of 'allowed' using a variadic template. Here is the code that I initially wrote using examples online:
template<typename... Args>
void CheckMethod(const http::verb& received, const Args&... allowed) const {
if((received != allowed) && ...) {
throw ApiError("method is not allowed")
}
}
However, this doesn't compile and results in an error:
error: expression contains unexpanded parameter pack 'allowed'
386 | if((received != allowed) && ... ) {
| ^ ~~~~~~~
1 error generated.
What fixed it was another set of parentheses:
if( ((received != allowed) && ...) )
The questions I used for reference: Variadic macro for checking if variable equals one of variadic arguments
Test if all elements are equal with C++17 fold-expression
So, why doesn't it work without the extra parentheses? Is it to do with how the expression is unpacked?
upd: I found out that a supposedly better way is to write
if(((received != allowed) && ...) == false) {
Can somebody please explain how and why this is better (if it is at all)?
You ask:
why doesn't it work without the extra parentheses?
And the boring answer is that that is just how the grammar for C++ works.
If you look here: https://en.cppreference.com/w/cpp/language/if you will see that a simple if
statement (if we remove the optional stuff) is:
if ( condition ) statement-true
So, if (1==2) doStuff();
is valid, but if 1==2 doStuff();
is not; the ()
are missing.
Then you can look at: https://en.cppreference.com/w/cpp/language/fold and see that a simple fold expression is:
( pack op ... )
This means that once again the ()
are a non-optional part of the grammar. So if you want to put this fold expression as the condition for an if
, then it just has to go: if (( pack op ...)) statement-true
because the inner ()
are a non-optional part of the fold, and the outer ones are a non-optional part of the if
.