I have an overloaded function that I have to call with many different types. The simple approach is:
uint8_t a;
uint16_t b;
//....
double x;
doSomething(a);
doSomething(b);
//...
doSomething(x);
expressing those calls succinctly can be done with a variadic template as explained at this Q&A. The code will look somewhat like this:
auto doSomethingForAllTypes = [](auto&&... args) {
(doSomething(args), ...);
};
uint8_t a;
uint16_t b;
//....
double x;
doSomethingForAllTypes(a, b, ... ,x);
But I'll have to do this at many places in the code, so I'd like to define the list of types only once. I'd like to have code that looks conceptually like this:
auto doSomethingForAllTypes = [](auto&&... args) {
(doSomething(args), ...);
};
someContainer allTypesNeeded(uint8_t, uint16_t, ... double);
doSomethingForAllTypes(allTypesNeeded);
How could this be done?
But for functions with arguments, we can call a function in two different ways, based on how we specify the arguments, and these two ways are: Call by Value. Call by Reference.
The main function always acts as a driver function and calls other functions. We can also write function call as a parameter to function.
Explanation: The function overloading is multiple functions with similar or different functionality but generic class functions perform the same task on given different types of data.
C Programming - Cannot Call Function More Than Once.
With some boiler-plate to obtain a tuple foreach, you can implement what you want as follows:
#include <tuple>
#include <utility>
namespace detail
{
template<typename T, typename F, std::size_t... Is>
void for_each(T&& t, F f, std::index_sequence<Is...>)
{
( static_cast<void>(f(std::get<Is>(std::forward<T>(t)))),... );
}
}
template<typename... Ts, typename F>
void for_each_in_tuple(std::tuple<Ts...> const& t, F f)
{
detail::for_each(t, f, std::index_sequence_for<Ts...>{});
}
int main() {
std::tuple<uint8_t, uint16_t, double> tup{};
for_each_in_tuple(tup, [](auto&& arg) {
doSomething(arg);
});
}
Live Example
If you want to have a predefined sequence of types you can use TypeList aproach if you don't want to create tuples with arguments:
#include <type_traits>
#include <utility>
void doSomething(int)
{
}
void doSomething(double)
{
}
template <typename... Args>
void doSomething(Args&&... args)
{
(doSomething(std::forward<Args>(args)), ...);
}
template <typename ...Args>
struct TypeList{};
template <typename T>
struct DoSomethingHelper;
template <typename ...Args>
struct DoSomethingHelper<TypeList<Args...>>
{
static void doSomething(Args&&... args)
{
::doSomething(std::forward<Args>(args)...);
}
};
template <typename T, typename ...Args>
void doSomethingForTypes(Args&&... args)
{
DoSomethingHelper<T>::doSomething(std::forward<Args>(args)...);
}
int main()
{
using MyTypeList = TypeList<int, double, int>;
doSomethingForTypes<MyTypeList>(1, 1.0, 2);
}
With std::tuple
and std::apply
std::tuple<uint8_t, uint16_t, double> tup{};
std::apply([](const auto&... arg) { (doSomething(arg), ...); }, tup);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With