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);
}
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);
}
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!