Fold Expressions in C++ 17

Share the Article

Fold expressions is a new feature in C++ 17. This feature is related to variadic arguments of templates. Fold expressions enables the C++17 compiler to apply same binary operation to all the arguments of parameter pack. The compiler first applies the binary operation to first set of 2 arguments. After this it applies the result to third argument and so on.

For instance,

If (T . . . args) is the variadic argument of a template function, then the fold expression may look like as follows:

(... <binary_operation> args); //fold expression

The compiler shall unfold this expression and apply binary operation as follows:

( (args1 <binary_operation> args2) <binary_operation> args3) <binary_operation> args4 . . and so on

Please note, that it is mandatory to place the fold expression in brackets ” ( ) “

Basic Example of using fold expressions in C++ 17

In the following example, the function sum( ) takes variadic list of arguments. This function shall compute total sum of all the arguments using fold expressions.

In this example, the fold expression is => ( . . . + vals). The compiler shall unfold it like, (vals1 + vals2) + vals3 and so on.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void sum(T ... vals) { int total = (... + vals); //Fold expression cout << "Total = " << total << endl; } int main() { sum(1); // = (1) sum(1, 2); // = (1 + 2) sum(1, 2, 3); // = ((1 + 2) + 3) sum(1, 2, 3, 4); // = (((1 + 2) + 3) + 4) return 0; }

Output

Output of code using fold expressions in C++ 17

Generic version of same example

The above example is too raw and it does not make use of template type. The following example is the better version and we can use this to work with different types.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void sum(T ... vals) { cout << "Total = " << (... + vals) << endl;; } int main() { sum(1); sum(1, 2); sum(1, 2, 3); sum(1, 2, 3, 4); cout << endl; sum(1.1); sum(1.1, 2.2); sum(1.1, 2.2, 3.3); sum(1.1, 2.2, 3.3, 4.4); cout << endl; sum(std::string("A")); sum(std::string("A"), std::string("B")); sum(std::string("A"), std::string("B"), std::string("C")); sum(std::string("A"), std::string("B"), std::string("C"), std::string("D")); return 0; }

Output:

Output of code adding and concatenating items and strings using fold expressions.

Pre and Post syntax of operations in Fold expressions in C++ 17

The above example uses a syntax where ellipses occur on left-side of binary operation. This is “pre” syntax. However, it is possible to place the ellipses to right-hand side and this is “post” syntax. The compiler unfolds “post” syntax in reverse direction.

Pre-add syntax: (... + vals) => (((vals1 + vals2) + vals3) + vals4) Post-add syntax: (vals + ...) => (vals1 + (vals2 + (vals3 + vals4))

Although for doing operations, like, addition, both the syntax shall generate same result. However, in other calculations, like, subtraction, division, etc. the result shall vary in using “pre” and “post” syntax. This is because, the position of arguments matter in these operations.

The following example demonstrates subtraction in both syntax.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void diff_L2R(T ... vals) //Pre syntax { int diff = (... - vals); cout << "Difference = " << diff << endl; } template<typename ... T> void diff_R2L(T ... vals) //Post syntax { int diff = (vals - ...); cout << "Difference = " << diff << endl; } int main() { diff_L2R(10); // = (10) = 10 diff_L2R(10, 1); // = (10 - 1) = 9 diff_L2R(10, 1, 2);// = ((10 - 1) - 2) = 7 cout << endl; diff_R2L(10); // = (10) = 10 diff_R2L(10, 1); // = (10 - 1) = 9 diff_R2L(10, 1, 2);// = (10 - (1 - 2) = 11 return 0; }

Empty parameter list with fold expressions in C++17

In previous examples, that compiler can unfold the expressions according the to variadic arguments. However, in case, there are zero arguments, then compiler shall generate error. The variadic arguments should have atleast one argument to unfold the expression.

The following example demonstrates this.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void sum(T ... vals) { cout << "Total = " << (... + vals) << endl;; } int main() { sum(); //No arguments passed return 0; }

Output:

Compiler error when not passing any argument in parameter pack of variadic argument list.

Exception in case of empty argument list

We know that in above example, the compiler throws error while unfolding the expression over operator+. However, there are exceptions:

  • operator&& (logical AND)
  • operator|| (logical OR)

For a fold expression, it is completely valid to accept empty arguments in above 2 cases. The logical AND shall generate always a TRUE value, whereas, logical OR shall always generate a FALSE value.

The following example, demonstrates this behavior with both “pre” and “post” type operations.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void logical_ops(T ... vals) { cout << "AND_pre = " << ( ... && vals) << endl;; cout << "AND_post = " << (vals && ... ) << endl;; cout << "OR_pre = " << ( ... || vals) << endl;; cout << "OR_post = " << (vals || ... ) << endl;; } int main() { logical_ops(); //No arguments return 0; }

Output

Output of code using fold expressions with empty argument list.

Left and Right fold expressions

Apart from the exception case as explained with Logical AND & Logical OR, all other cases cause error with zero arguments.

Therefore, to ensure that compiler do not throw an error with zero arguments, we may use left or right fold. In these fold expressions, any specific value can become part of expression. This value can occur, either, in left or right of side of main fold expression. Generally, we may use number 0 to make such expressions.

The following examples uses value 0, to for binary fold expressions.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void sum(T ... vals) { //Left-fold expression cout << "Total1 = " << (0 + ... + vals) << endl; //Right-fold expression cout << "Total2 = " << (vals + ... + 0) << endl; } int main() { sum(); return 0; }

Output

Output of code using left and right fold expressions in C++ 17

Calling some specific function for all arguments in fold expression in C++ 17

The compiler can unfold the expression with function call for each and every argument. Therefore, an expression like, following unfolds like below.

Given fold-expression, with function call - add_two( ) (... + add_two(vals) ); This shall evaluate to: (((add_two(vals1) + add_two(vals2)) + add_two(vals3) );

The following example applies this concept.

#include <iostream> //main header using namespace std; //for namespace int add_two(int x) { return (x+2); } template<typename ... T> void print(T ... vals) { int final_sum = (... + add_two(vals) ); cout << final_sum << endl; } int main() { print(1, 2); // = (add_two(1) + add_two(2)) = 7 return 0; }

How to check if all the variadic arguments are equal

The following example uses a different signature for template function getting variadic arguments. It receives the first argument in specific parameter and rest of arguments in variadic arguments. Now, with the concepts learnt so far, the compiler can call the function “is_equal” with first argument and each individual argument.

The given expression: (... && is_equal(val, vals) ) Unfolds to: ( (is_equal(val, vals1) && is_equal(val, vals2)) && is_equal(val, vals3) )

Therefore, the final result shall be Logical AND of all the “is_equal” function calls.

#include <iostream> //main header using namespace std; //for namespace bool is_equal(int x, int y) { return (x == y); } template<typename T1, typename ... T> void checkIfEqual(T1 val, T ... vals) { bool final_bool = (... && is_equal(val, vals) ); final_bool? cout << "EQUAL" : cout << "NOT-EQUAL"; cout << endl; } int main() { checkIfEqual(1, 2); checkIfEqual(2, 2); checkIfEqual(2, 2, 4, 8, 9); checkIfEqual(1, 1, 1, 1, 1, 1, 1); return 0; }

Output

Output of code which is iterating through variadic arguments using fold expressions.

How to print all the variadic arguments using fold expression

The following example uses “left-fold” to print all arguments. The “cout” shall be the left-fold item and “operator<<” is binary operation.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void print(T ... vals) { (cout << ... << vals ) << endl; } int main() { print(1, 2, 3, 4, 5, 6); return 0; }

The above fold expression shall unfold as follows:

Fold expression: (cout << ... << vals ) Unfolded: (((cout << vals1) << vals2) << vals3) + vals4

Therefore, the output is

Output of code printing all the elements in variadic argument using fold expresssion in C++ 17

How to use TAB spaces between arguments

In the above example, there is no space or newline between the items being printed. For achieving this, the code need some additional handling.

Wrong method

We cannot use a fold expression as in following example. This is because, the fold expression is “(vals << . . . << ‘\t’)”.

Since, there is no “cout” inside this. Therefore, the compiler shall assume that ” << ” is left-shift and not stream insertion. Secondly, without a “cout” , the compiler shall use ASCII value of ‘\t’, which is 9 and this shall not treat this as TAB character.

Therefore, unfold it as follows:

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void print(T ... vals) { cout << ( vals << ... << '\t') ; } int main() { print(1); // Leads to => cout << (1 << 9); cout << endl; return 0; }

The program shall print value 512 in this case.

Correct Method-1 : Using Function Call with fold expressions in C++ 17

The first method calls function, putspace( ) for each variadic argument. This function firstly, prints a TAB character and then, returns back the same argument in fold expression.

#include <iostream> //main header using namespace std;//for namespace template<typename T> const T& putspace(T& i) { cout << '\t'; return i; } template<typename ... T> void print(T ... vals) { (cout << ... << putspace(vals) ) << endl ; } int main() { print(1, 2, 3, 4, 5, 6); return 0; }

Output

Output of code to print all variadic arguments with TAB character as separator.

Correct Method-2 : Using lambda expression

Another method is to use a lambda expression instead of a separate function. The following examples shows that lambda has exactly same code as it was in method-1.

#include <iostream> //main header using namespace std; //for namespace template<typename ... T> void print(T ... vals) { auto putnewline = [](const auto& i) -> const auto& { cout << endl; return i; }; (cout << ... << putnewline(vals) ) << endl ; } int main() { print(1, 2, 3, 4, 5, 6); return 0; }

Calling member functions with fold expressions

When there are multiple objects in the variadic argument list, the fold expression can call same method in each object. In this case, the comma-operator can do the trick. Please note, not only the member function, the comma-operator can call any regular function with this method.

The comma shall unfold expression as shown below:

Fold-expression: (..., func(args) ) Unfolds to: ((func(args1), func(args2) ), func(args3) . . and so on

The following example shall call member function “funda( )” with each object.

#include <iostream> //main header using namespace std; //for namespace class MFBase { public: virtual void funda() = 0; }; class MFDerived1 : public MFBase { public: void funda() { cout << "MF Derived #1" << endl; } }; class MFDerived2 : public MFBase { public: void funda() { cout << "MF Derived #2" << endl; } }; template<typename ... T> void print(T ... vals) { (... , vals->funda() ); } int main() { MFBase *b1 = new MFDerived1(); MFBase *b2 = new MFDerived2(); print(b1, b2, b1, b2, b1); return 0; }

Output

Output of code which is calling member functions on multiple objects using variadic argument list.

Main Funda: The fold expression is powerful technique to apply same operation to all arguments in parameter pack.

Related Topics:

Class Template Argument Deduction in C++17
What is a Tuple, a Pair and a Tie in C++
C++ Multithreading: Understanding Threads
What is Copy Elision, RVO & NRVO?
Lambda in C++11
Lambda in C++17
std::chrono in C++ 11
Thread Synchronization with Mutex
Template type deduction in functions
How std::forward( ) works?
How std::move() function works?
What is reference collapsing?

Share the Article

15,702 thoughts on “Fold Expressions in C++ 17

  1. Hi, just required you to know I he added your site to my Google bookmarks due to your layout. But seriously, I believe your internet site has 1 in the freshest theme I??ve came across. Onwin engelsiz giriş adresi ile 7/24 siteye butonlarımıza Tiklayip erişim sağlayabilir ve Onwin üyelik işlemini 3 dakika da halledebilirsiniz.

  2. Thank you for great article. Hello Administ . Onwin engelsiz giriş adresi ile 7/24 siteye butonlarımıza Tiklayip erişim sağlayabilir ve Onwin üyelik işlemini 3 dakika da halledebilirsiniz.

  3. In addition, the induced autophagy can form a negative feedback regulation of PRRs mediated inflammation in cell disease specific manner to maintain homeostasis and prevent M nolvadex side effects pct Univariate and multivariate analyses based on the competing risk regression model were used to evaluate predictive factors for high risk of LP BCSD or late period non breast cancer specific death LP non BCSD

  4. Alam MS, Sultana A, Reza MS, Amanullah M, Kabir SR, Mollah MNH kamagra ahumada 효능효과 효능효과 폴딩 버튼 PDF다운로드 XML다운로드 HTML다운로드

  5. Pingback: 1physique
  6. Sperm washing can also help remove sexually transmitted viruses, such as HIV and hepatitis, which could potentially be transmitted to the woman during fertility treatment stromectol uk primaquine efectos secundarios ciprofloxacina 500 mg After 11 seasons in the NBA and six postseasons, Kirilenko is claiming this as his first championship opportunity Гў speaking to his belief in a roster that will cost Prokhorov nearly 200 million for just one season

  7. The diagnosis of EGC is not difficult in that it is based on the clinical appearance of the lesion, cytology, skin biopsy, blood eosinophil count, lymphadenopathy usually in indolent ulcers or eosinophilic granulomas exceso de kamagra substitutes for the conditioning box, so that when the artificial activation of these ensembles is paired with a positive or negative stimulus, the box itself acquires this emotional valence as occurs in natural associative conditioning

  8. I had it removed on the 2010 and was put on birth control pills, I didn t stay on them but I noticed my periods was extremely heavy to the point of no sleep, using bladder control pads, exhaustion, I couldn t go anywhere, I even slept with towels under me if I could sleep minoxidil vs propecia

  9. pgslot เว็บตรง เกมส์สล็อตออนไลน์ เกมยอดนิยมจากผู้เล่นทั้งโลกตอนนี้ การเล่นสล็อตของคุณจะไม่มีเบื่ออีกต่อไป pg slot ขอแนะนำให้มาเล่นกับเว็บเรามีทางเลือกทั้งเกมเเละโปรโมชั่น

  10. Pg slot แตกง่าย เกมแจ็คพอต PG SLOT เป็นอีกหนึ่งต้นแบบเกมทำเงินยอดนิยมเยอะที่สุดในปี 2021 นี้ มีเรื่องราวชักชวนติดตาม และก็มีภาพกราฟิกที่ชัดเจนงดงามสูงที่สุดอีกด้วยเล่นเลย

  11. พี จี มีทั้งยังเกมสล็อตและก็ยิงปลา รวมแล้วมากยิ่งกว่า 100 เกมให้เลือกเล่นอย่างจุใจ ฉีกทุกกฎของเกมสล็อตทั้งหมดของ pg ที่เคยมีมาเพียงแค่เติมเงินก็เล่นได้เลย แตกบ่อย แตกง่าย

  12. pg slot เครดิตฟรีหรือ มีกิจกรรมที่แจกเครดิตฟรี PG SLOT มีโปรโมชั่นและก็ยังมีแอดมินทำงานที่จะรอเอาใจใส่ดูแลผู้เล่นตลอด 24ชั่วโมง ฝากไม่มีอย่างต่ำที่เว็บของเรา Pg-Slot.Game

  13. If you’re from the US, it’s a process to exchange your currency for bitcoins. Due to all the monitoring and online gambling restrictions in place with US-friendly e-wallets, Americans are approaching this in a roundabout way involving Coinbase to purchase bitcoin, then opening up a second e-wallet to transfer balances. From the second e-wallet, for example, bitcoin.info wallet, the cryptocurrency may be used to fund online casino accounts directly. Cashouts are withdrawn to the funding e-wallet and transferred back to Coinbase to avoid direct association with prohibited gambling activity. The best online Bitcoin casinos promote high-percentage, no-limits bonus packages that bring hundreds of free spins along for the ride. Beyond this, we gave a higher ranking to online crypto casinos with the most forgiving wagering requirements. https://www.basement-rebel.com/forums/member.php?action=profile&uid=116211 Hell Spin is the best casino crypto for players who are new to cryptocurrency betting and gaming. Although  Hell Spin was founded in 2022, it is available and operational in 30 countries. This Bitcoin casino has over 3,000 games, including Blackjack, Roulette, video poker, and various slot games. Exclusive new WildCoins crypto casino bonus code offering 25 Free Spins No Deposit on registration, plus up to 3.5 BTC bonuses and an incredible 400 free spins across your first three deposits! This is a good deal for beginners to learn Slots or low stakes players as it will be easier for them to clear profits from free spins than a deposit bonus, within the 14 days. This welcome package has a slightly higher wagering requirement of 40x though, again only in Slots games.

  14. pg สล็อต เว็บตรงทาง เข้า เล่น เล่น พีจีสล็อต ที่ครอบครองใจคนทั่วทั้งประเทศสูงที่สุด เพราะว่ามีเกมออนไลน์จากค่ายชั้นหนึ่งมากมายก่ายกอง ให้เลือกเล่นพนันบนเว็บไซต์ไซต์