Variadic expander without typedef

One trick, which is often used to expand parameter variation, uses a non-standard typedef array in combination with a comma operator, as shown below:

#include <iostream> template<typename... Ts> void expander(Ts&&... ts) { using expand = int[]; (void)expand{0, (std::forward<Ts>(ts)(), 0)...}; } void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; } int main() { expander(f, f); } 

Live on coliru

Can we do this without typing typedef? If I try straight

 (void)int[]{0, (std::forward<Ts>(ts)(), 0)...}; 

gcc / clang spit out

error: expected primary expression before 'int'

and if I try to put in brackets, the compilation of the code, but I believe that it is non-standard:

warning: ISO C ++ forbids compound literals [-Wpedantic]

+5
source share
4 answers

In this expression

 (void)int[]{0, (std::forward<Ts>(ts)(), 0)...}; 

You are trying to use functional notation to create a temporary array. This will not work, because the language allows the use of functional notation only using a simple type specifier or a typename specifier.

From [expr.type.conv] / 3

Similarly, the simple-type-specifier or typename-specifier, followed by the braced-init-list, creates a temporary object of the specified type with a direct initialization list (8.5.4) with the specified braced-init-list, and its value is that the temporary object is like a prvalue.

And if you move on to defining a simple specifier type in [dcl.type.simple] , it does not contain anything with array brackets. In fact, it does not even contain anything more than one word. This is why the int(1) entry is valid, but signed int(1) not.

So, with C ++ 11/14 you need to typedef or declare an array variable. But with the C ++ 1z compiler, you can use bend expressions and avoid both

 template<typename... Ts> void expander(Ts&&... ts) { (void(std::forward<Ts>(ts)()), ...); } 

Live demo

+5
source

Can this be done without introducing typedef?

Without typedef, but with a variable

 template<typename... Ts> void expander(Ts&&... ts) { int dummy[] = {0, (std::forward<Ts>(ts)(), void(), 0)...}; (void) dummy; } 
+5
source

In C ++ 17, you can do this with folds like:

 template<typename... Ts> void expander(Ts&&... ts) { (..., std::forward<Ts>(ts)()); } 

Live demo

+3
source

You can do it as follows:

 #include <iostream> template<typename... Ts> void expander(Ts&&... ts) { int dummy[sizeof...(Ts)] = {(std::forward<Ts>(ts)(), 0)...}; } void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; } int main() { expander(f, f, f); expander(); } 

https://ideone.com/BzNXhD

+1
source

Source: https://habr.com/ru/post/1242408/


All Articles