带有可变参数模板参数的广义函子

问题描述 投票:0回答:1

我目前正在阅读 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
};

您能给我一些关于如何改进我的代码的建议吗?谢谢你。

c++ templates variadic-templates
1个回答
0
投票

如果目的是限制函子的参数并在单个模板参数中返回值,您可以这样做。我首先定义三个主要类模板:

#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)...);
    }
};

因此,在每个阶段,您都将复合类型作为单个模板参数传递,然后将其拆分为专业化。

演示

© www.soinside.com 2019 - 2024. All rights reserved.