Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ call function with many different types

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?

like image 363
marco Avatar asked May 06 '19 07:05

marco


People also ask

How many ways can C call function?

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.

Can C functions call other functions?

The main function always acts as a driver function and calls other functions. We can also write function call as a parameter to function.

What makes it possible to use one function or class to handle many different data types?

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.

Can a function be called multiple times in C?

C Programming - Cannot Call Function More Than Once.


3 Answers

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

like image 116
StoryTeller - Unslander Monica Avatar answered Oct 19 '22 16:10

StoryTeller - Unslander Monica


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);
}
like image 37
Dmitry Gordon Avatar answered Oct 19 '22 17:10

Dmitry Gordon


With std::tuple and std::apply

std::tuple<uint8_t, uint16_t, double> tup{};
std::apply([](const auto&... arg) { (doSomething(arg), ...); }, tup);
like image 1
Jarod42 Avatar answered Oct 19 '22 16:10

Jarod42