Home > OS >  For-loop with conditional call of a variadic amount of functions
For-loop with conditional call of a variadic amount of functions

Time:11-10

Instead of performing recursive calls, I want an arbitrary number of functions to trigger based on some condition in a loop. How do I transform method0, method1 to be called for a variadic number of typename ... methods?

Edit: As you cannot return a variadic number of types, I modified the example a litte.

template <typename method0, typename method1, typename ... Args>
void loop(Args ... args)
{
    for (int i = 0; i < iter_max; i  )
    {
        if (method0::condition(args))
        {
            method0::call_modify(args);
        }
        if (method1::condition(args))
        {
            method1::call_modify(args);
        }
        //...
    }
}

template<typename ... Args>
struct method0
{
    static bool condition(Args& ... args)
    {
        //Trigger condition
    }

    static void call_modify(Args& ... args)
    {
        //Perform action on args
    }
};

CodePudding user response:

You can do it like this:

#include <iostream>

template<typename ... Args>
struct method0
{
    static bool condition(Args& ... args)
    {
        std::cout << "condition \n";
        return true;
    }

    static void call(Args& ... args)
    {
        std::cout << "call\n";
    }
};


template <typename... Methods, typename ... Args>
void loop(Args ... args)
{        
    auto apply = []<typename m>(auto&... a){
        if (m::condition(a...)) m::call(a...); 
    };
    (apply.template operator()<Methods>(args...), ...);
}

int main() {
    loop<method0<int,int>,method0<int,int>>(1,2);
}

Output:

condition 
call
condition 
call

Perhaps loop should take references too in that case. And I ommitted the loop, it should be trivial to add it.


This is the old version of the answer for the slightly simpler case of non-variadic condition and call:

struct A {
    static bool condition(int x) { 
        std::cout << "A::condition " << x << "\n";
        return true;
    }
    static int call(int) { 
        std::cout << "A::call\n";
        return 42;
    }
};
struct B {
    static bool condition(int x) { 
        std::cout << "B::condition " << x << "\n";
        return false;
    }
    static int call(int) { 
        std::cout << "B::call\n";
        return 0;
    }
};

You can make loop call n-th types condition and call with n-th args like this:

template <typename... Methods, typename ... Args>
void loop(Args ... args)
{
    auto apply = []<typename m>(auto& a){
        if (m::condition(a)) a = m::call(a); 
    };
    (apply.template operator()<Methods>(args), ...);
}


int main() {
    loop<A,B>(1,2);
}

Output:

A::condition 1
A::call
B::condition 2

CodePudding user response:

I managed to generalize 463035818_is_not_a_number's answer to be looped, and to take on a variadic number of input arguments. Full working example:

#include <iostream>

struct method0
{
    static bool condition(double &arg1, double &arg2)
    {
        // Trigger condition
        return (arg1 <= arg2);
    }

    static void call_modify(double &&arg1, double &&arg2)
    {
        std::cout << "method0!" << std::endl;
        arg1  = 1;
    }
};

struct method1
{
    static bool condition(double &arg1, double &arg2)
    {
        // Trigger condition
        return (arg1 > arg2);
    }

    static void call_modify(double &&arg1, double &&arg2)
    {
        std::cout << "method1!" << std::endl;
        arg1 -= 1;
    }
};

template <int iter_max, typename... Methods>
struct wrapper
{
    template <typename... Args>
    static void loop(Args &...args)
    {
        auto apply = []<typename m>(auto&&... a)
        {
            if (m::condition(a...))
                m::call_modify(std::forward<Args>(a)...);
        };
        for (int i = 0; i < iter_max; i  )
        {
            (apply.template operator()<Methods>(std::forward<Args>(args)...), ...);
        }
    }
};

int main()
{
    double arg1 = 2.0;
    double arg2 = 0.;
    constexpr int iter_max = 5;
    wrapper<iter_max, method0, method1>::loop<double, double>(arg1, arg2);
}

output:

method1!
method1!
method0!
method1!
method0!
method1!
method0!
method1!
  • Related