I'm currently reading Modern C++ Design by Andrei Alexandrescu and, in Chapter 5, the author discusses generalized functors as a alternative to the classic Command pattern. Although I'm completely newbie when it comes to metaprogramming, I could realize the book (or at least the edition I'm reading) is not updated with the modern C++ features, so I decided, as a personal challenge, to implement Alexandrescu's ideas using variadic templates and, to a certain extent, I was sucessful:
template <typename R, typename... Args> class FUNCTORIMPLEMENTATION{
public:
virtual R operator()(Args&&... args)=0;
virtual ~FUNCTORIMPLEMENTATION(){}
};
template <typename F, typename P, typename R, typename... Args> class FUNCTORHANDLER : public FUNCTORIMPLEMENTATION<R, Args...>{
private:
F functor;
public:
FUNCTORHANDLER(const F& functor) : functor(functor){}
R operator()(Args&&... args){return functor(std::forward<Args>(args)...);}
};
template <typename R, typename... Args> class FUNCTOR{
private:
FUNCTORIMPLEMENTATION<R, Args...>* implementation;
public:
template <typename F> FUNCTOR(const F& functor):implementation(new FUNCTORHANDLER<F, FUNCTOR, R, Args...>(functor)){}
R operator()(Args&&... args){return (*implementation)(std::forward<Args>(args)...);}
};
class TESTFUNCTOR
{
public:
float operator()(int i, double d){
return i+d;
}
};
int main(){
TESTFUNCTOR functor;
FUNCTOR<float, int, double> command(functor);
float result=command(1, 1.2);
return 0;
}
As you can see, the code is pretty ugly. One of the biggest issues lies on the declaration of FUNCTORHANDLER. I was unable to find a way to pass FUNCTOR<R, Args...> as a single template argument to the FUNCTORHANDLER's constructor, so I had to declare R and Args... as separate arguments in the FUNCTORHANDLER's template list. I wish I could have implemented something like this:
template <typename R, typename... Args> class FUNCTORIMPLEMENTATION{
public:
virtual R operator()(Args&&... args)=0;
virtual ~FUNCTORIMPLEMENTATION(){}
};
template <typename F, typename P> class FUNCTORHANDLER : public FUNCTORIMPLEMENTATION<typename P::RType, typename P::ArgsType...>{//R and Args should not be in the FUNCTORHANDLER's template list
private:
F functor;
public:
FUNCTORHANDLER(const F& functor) : functor(functor){}
R operator()(Args&&... args){return functor(std::forward<Args>(args)...);}
};
template <typename R, typename... Args> class FUNCTOR{
private:
FUNCTORIMPLEMENTATION<R, Args...>* implementation;
public:
template <typename F> FUNCTOR(const F& functor):implementation(new FUNCTORHANDLER<F, FUNCTOR<R, Args...>>(functor)){} //FUNCTOR<R, Args...> must be passed as a single template parameter
R operator()(Args&&... args){return (*implementation)(std::forward<Args>(args)...);}
using RType=R;
using ArgsType=Args;//this is wrong, I don't know how to type aliase a pack expansion
};
Could you give me some advice on how to improve my code? Thank you.
std::tuple<Args...>. To passRandArgsin a single template parameter, you can useR(Args...). Anyway it's not clear enough for me to write a full answer.std::function.