我目前正在阅读 Andrei Alexandrescu 的《Modern C++ Design》,在第 5 章中,作者讨论了广义函子作为经典命令模式的替代方案。虽然在元编程方面我完全是新手,但我可以意识到这本书(或者至少是我正在阅读的版本)并未使用现代 C++ 功能进行更新,因此我决定作为个人挑战来实现 Alexandrescu 的想法使用可变参数模板,在某种程度上,我成功了:
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;
}
如您所见,代码非常丑陋。最大的问题之一在于
FUNCTORHANDLER
的声明。我无法找到一种方法将 FUNCTOR<R, Args...>
作为单个模板参数传递给 FUNCTORHANDLER
的构造函数,因此我必须将 R 和 Args... 声明为 FUNCTORHANDLER
的模板列表中的单独参数。我希望我能实现这样的事情:
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
};
您能给我一些关于如何改进我的代码的建议吗?谢谢你。
如果目的是限制函子的参数并在单个模板参数中返回值,您可以这样做。我首先定义三个主要类模板:
#include <memory>
#include <type_traits>
#include <utility>
#include <iostream>
// primary class templates, unimplemented:
template <class...> class FUNCTORIMPLEMENTATION;
template <class...> class FUNCTORHANDLER;
template <class...> class FUNCTOR;
这三个专业化将传递的类型分为几个部分:
// specialization for FUNCTORIMPLEMENTATION to match on R(Args...)
template <class R, class... Args>
class FUNCTORIMPLEMENTATION<R(Args...)> {
public:
virtual R operator()(Args&&... args) = 0;
virtual ~FUNCTORIMPLEMENTATION() {}
};
FUNCTORHANDLER
甚至可以使用FUNCTOR
主要来验证它是基于FUNCTOR
的类型:
// specialization for FUNCTORHANDLER to match on F and the FUNCTOR<R(Args)...>
template <class F, class R, class... Args>
class FUNCTORHANDLER<F, FUNCTOR<R(Args...)>> : public FUNCTORIMPLEMENTATION<R(Args...)> {
private:
F m_functor;
public:
template<class Ff>
FUNCTORHANDLER(Ff&& functor) : m_functor(std::forward<Ff>(functor)) {}
R operator()(Args&&... args) override {
return m_functor(std::move(args)...); // Args&& is not a forwarding ref
}
};
// specialization for FUNCTOR to match on R(Args...)
template <class R, class... Args>
class FUNCTOR<R(Args...)> {
private:
std::unique_ptr<FUNCTORIMPLEMENTATION<R(Args...)>> implementation;
public:
template <class F>
FUNCTOR(F&& functor)
: implementation(
std::make_unique<FUNCTORHANDLER<F, FUNCTOR<R(Args...)>>>
(std::forward<F>(functor))) {}
R operator()(Args&&... args) {
return (*implementation)(std::move(args)...);
}
};
因此,在每个阶段,您都将复合类型作为单个模板参数传递,然后将其拆分为专业化。