Welcome to the next pikoTutorial !
What is a folding expression?
Imagine that you have a vector of integers and you need to add some predefined values to it. The obvious choice seems to be just using push_back() function applied a couple of times:
# include <vector>
int main()
{
std::vector<int> vec;
vec.push_back(-3);
vec.push_back(5);
vec.push_back(8);
vec.push_back(12);
vec.push_back(47);
}This works, but look how much vertical space it took and how many times you had to call push_back() function. To make it more concise, we could define a function which uses a C++ folding expression. Such expression applies certain function (in this case push_back()) to all elements of the parameters pack:
# include <vector>
template <typename ... Args>
void PushBackAtOnce(std::vector<int> &vec, Args&& ... args)
{
(vec.push_back(std::forward<Args>(args)), ...); // folding expression
}
int main()
{
std::vector<int> vec;
PushBackAtOnce(vec, -3, 5, 8, 12, 47);
}Folding expressions and function overloading
Such syntax can be also combined with the function’s overloading. In such case, you can apply a different implementation of the function to each of the parameters pack element, depending on the type of that element.
#include <iostream>
// implementation for integer type
void Process(const int input)
{
std::cout << "Doing something with an integer..." << std::endl;
}
// implementation for float type
void Process(const float input)
{
std::cout << "Doing something with a float..." << std::endl;
}
template <typename ... Args>
void DoSomething(Args&& ... args)
{
(Process(std::forward<Args>(args)), ...);
}
int main()
{
DoSomething(12, 24.0F);
}The output of the above code is:
Doing something with an integer...
Doing something with a float...Potential pitfalls
You must remember that when your code relies fully on function overloading within a folding expression, you are responsible for providing overloaded function implementations for all the types – otherwise, the compilation will fail. In the example above I can add just one more argument 24.0 at the end and the compilation fails:
DoSomething(12, 24.0F, 24.0);Literals like 24.0 (without F suffix) are resolved to a double type and because there’s no implementation of Process() function for double, compiler reports an error. In such case you must either provide such implementation or create a generic function which will perform some default behavior for all the types which don’t have their dedicated implementations. For example:
// generic implementation
template <typename T>
void Process(const T input)
{
std::cout << "Unknown type - skipping..." << std::endl;
}Now, the program compiles again and the output is:
Doing something with an integer...
Doing something with a float...
Unknown type - skipping...Read also:
- GTest and short-circuit evaluation in C++
- AI is powerful. Snippets are instant.
- From AUTOSAR to S-Core: the first C++ pub/sub implementation
- How to write Arduino Uno code with Python?
- Combining Bazel with Docker
- Running commands with timeout on Linux
- Running Python unit tests with CMake
- Thirdparty dependencies with FetchContent
- Bug of the week #11
- Combining CMake with Docker
- How to search the internet from Linux terminal?
- Folding expressions in C++
- How to derive from an enum in Python?
- Bug of the week #10
- Trying ROS2: client/server within a single container
- Make C++ a better place #4: Go as an alternative
- How to convert hex to dec in Linux terminal?
- Setting up a Python project with CMake
- Separating builds for different configs with Bazel
- Trying ROS2: pub/sub within a single container
- Bug of the week #9
- UDP multicasting with Python
- Destruction order vs thread safety in C++
- Let’s review some code: C++ #2
- Make C++ a better place #3: D as an alternative
- Registering callback using std::function in C++
- Bug of the week #8
- TCP client/server with Python
- Simple menus in Bash scripts with select
- Calling member function on a nullptr in C++
- Bug of the week #7
- Python lru_cache explained
- How to dockerize a Python application?
- Make C++ a better place #2: CppFront as an alternative
- Parameters combinations in GoogleTest
- Data transfer with curl
- Python reduce explained
- Bug of the week #6
- Custom literals in C++
- Linux and hash command
- 5 Python good practices which make life easier
- Let’s review some code: Python #1
- Make C++ a better place #1: What does better mean
- Enums vs enum class in C++
- Bug of the week #5
- UDP client/server with Python
- Hard links in Linux
- Functions calling order in unit tests in C++
- Bug of the week #4
- Yield in Python – state machines, coroutines and more
- Copy files from another branch with Git
- Make C++ a better place #0: Introduction
- 5 misconceptions about std::move in C++
- How to use xargs on Linux?
- How to test method call order with unittest in Python?
- Bug of the week #3
- Build & run C++ unit tests with CMake
- Arrange text with sort on Linux
- Key derivation function with Python
- Let’s review some code #1: C++









