Run Callable on each Argument
A C++ template function that runs a given callable (function or lambda) on each of its arguments, with compatibility for pre-C++17 compilers.
The Problem
Sometimes you need to apply the same function or operation to multiple arguments of possibly different types. While C++17 provides fold expressions for this, you may need to support older compilers.
The Solution
Here’s a template function that applies a callable to each argument:
For C++17 and later
With C++17 fold expressions, this becomes elegantly simple:
template<typename F, typename ...T>
void for_each_arg(F&& function, T&&... args) {
(function(std::forward<T>(args)), ...);
}
For pre-C++17 compilers
For compatibility with older standards, use this workaround:
template<typename F, typename ...T>
void for_each_arg(F&& function, T&&... args){
int pass[]{ ((function(std::forward<T>(args)), 0)... };
(void)pass;
}
How It Works
C++17 Version
- Uses a fold expression with the comma operator
std::forward<T>(args)ensures perfect forwarding- The fold expression expands to
function(arg1), function(arg2), ...
Pre-C++17 Version
- Creates an array using brace initialization
- The comma operator ensures
function(arg)is called, then0is stored in the array (void)passsuppresses unused variable warnings- The pack expansion
...applies this to all arguments
Usage Example
#include <iostream>
// Example callable
auto print = [](const auto& value) {
std::cout << value << " ";
};
int main() {
for_each_arg(print, 1, 2.5, "hello", 'c');
// Output: 1 2.5 hello c
return 0;
}
Key Features
- Perfect forwarding: Preserves value categories of arguments
- Template metaprogramming: Works with any callable and argument types
- Backward compatibility: Supports pre-C++17 compilers
- Zero runtime overhead: Everything is resolved at compile time
This technique is useful for debugging, logging, or any scenario where you need to apply the same operation to multiple heterogeneous arguments.