Here is some code that not work:
#include<iostream>
template<typename T1, typename T2, typename T3>
class Composer {
// pseudocode of constructor
template<typename... Args_one, typename... Args_two, typename... Args_three>
explicit Composer(Args_one...args1, Args_two...args2, Args_three...args3) {
t1_ = T1(args1...);
t2_ = T2(args2...);
t3_ = T3(args3...);
}
double operator()(int u) {
auto x1 = t1_(u);
auto x2 = t2_(float(x1));
auto x3 = t3_(double(x2));
return x3;
}
private:
T1 t1_;
T2 t2_;
T3 t3_;
};
class StageOne {
public:
StageOne(int a, int b): a_(a), b_(b) {};
int operator()(int c) const {
return a_ + b_ + c;
}
private:
int a_;
int b_;
};
class StageTwo {
public:
StageTwo(float c, float d): c_(c), d_(d) {};
float operator()(float i) const {
return c_ + d_ + i;
}
private:
float c_;
float d_;
};
class StageThree {
public:
StageThree(double x, double y): x_(x), y_(y) {};
double operator()(double z) const {
return (x_ + y_) * z;
}
private:
double x_;
double y_;
};
int main()
{
Composer<StageOne, StageTwo, StageThree> composer{{3, 4}, {1.2f, 2.3f}, {4.5, 3.3}};
std::cout << composer(3) << std::endl;
}
The Composer
template is used to chain three functors. Each functors need to be initializd.
I know I can add methods like setStageOne
that utilize a single parameter pack to do the initialization, but I will have to add three such methods and cannot forget to call it afterwards.
So I want the Composer
's constructor take the work to set up the functors. Is there a way to do it?
You could put the arguments in std::tuple
s. Since the types are not default-constructible, you'll need a helper to initialize them from the supplied argument via std::apply
(called init
below).
Example:
#include <tuple>
#include <utility>
template <class T1, class T2, class T3>
class Composer {
template <class T, class... Args>
T init(std::tuple<Args...>& t) {
return std::apply(
[](auto&&... args) {
return T{std::forward<decltype(args)>(args)...};
}, t);
}
public:
template <class... Args_one, class... Args_two, class... Args_three>
explicit Composer(std::tuple<Args_one...> args1,
std::tuple<Args_two...> args2,
std::tuple<Args_three...> args3)
: t1_(init<T1>(args1)), t2_(init<T2>(args2)), t3_(init<T3>(args3)) {}
double operator()(int u) {
auto x1 = t1_(u);
auto x2 = t2_(float(x1));
auto x3 = t3_(double(x2));
return x3;
}
private:
T1 t1_;
T2 t2_;
T3 t3_;
};