C++ C++;设计:函数结果的全局存储

C++ C++;设计:函数结果的全局存储,c++,c++11,memoization,C++,C++11,Memoization,考虑以下代码(根据gcc 4.7.2编译): 好的,简短问题的长前奏。这里会出现一些冗余计算,例如,A()(x)的结果会计算六次(一些通过对象,一些通过指针)。如何实现存储计算函数值的全局输出数组 我想到的一种方法应该是实现每个(组合)类唯一的函数std::string id(),外加一个全局std::map来存储结果,然后检查(当前)结果是否存在 你有没有看到其他更好的方法?提前谢谢 抱歉,伙计们,虽然有一些相似之处(单词“memorization”似乎在某种程度上触发了一种反射),但我真

考虑以下代码(根据gcc 4.7.2编译):

好的,简短问题的长前奏。这里会出现一些冗余计算,例如,A()(x)的结果会计算六次(一些通过对象,一些通过指针)。如何实现存储计算函数值的全局输出数组

我想到的一种方法应该是实现每个(组合)类唯一的函数
std::string id()
,外加一个全局
std::map
来存储结果,然后检查(当前)结果是否存在

你有没有看到其他更好的方法?提前谢谢



抱歉,伙计们,虽然有一些相似之处(单词“memorization”似乎在某种程度上触发了一种反射),但我真的不明白为什么这应该是重复的。。。但我愿意讨论

在我看来,上述情况比链接线程中的情况要复杂得多(例如,它不仅仅是一个斐波那契函数)。此外,据我所知,高亮显示的memonization类将以不同的方式处理对象和指针(至少在不进行进一步编辑的情况下)。我的意图是得出一种模式,其中每个结果只计算一次,并考虑如何调用它

到目前为止,我一直在使用CRTP的静态结果类,这导致了以下代码(使用GCC4.7.2编译):

好的,这里需要注意一些事情:

  • 通过从staticresults类继承,有趣的是,所有不同名称的A(按对象、按指向对象的指针、按指向基的指针)如何检索存储的结果(只有一个集合)。C()也一样,调用了三次,但只设置了一次

  • 为了预测下一个反射,我知道多重继承可能是不好的,但是类之间似乎很好地分开了。同样的行为可能是通过合成得到的,所以请忘记这一点

  • 事实上,这还不是一个真正的记忆类,因为它只是存储首先计算的结果。因此,它也给出了错误的结果[例如,对于C(B(A))]。然而,这可以很容易地通过地图或其他方式解决。我最终会这样做的,目前只是关于模式(EDIT:is done)

  • 作为最后一点,我知道,与看似重复的线程不同的解决方案并不意味着不同的问题。然而,它可能(--希望)会对本页的记忆主题进行一些扩展,所有人都能从中受益

    我期待着你的想法。提前谢谢



    编辑2:帮助自己是一件好事,现在的代码工作,因为我一直在寻找。我已经在上面的帖子中更新了它

    变化:

  • 添加了一张地图,让它成为一个真正的记忆类。注意:双重比较是危险的,所以最好传递一个更合适的比较函数,而不是标准等式

  • 使结果数组的静态成员私有,并保护setter,因为只有函数类可以更改结果

  • 但是,贴图类型不是由模板参数提供的(如链接线程中)。这是我不需要的开销(也可能是YAGNI)


  • 现在我不再自言自语了。欢迎评论。谢谢,David,你的代码有未定义的行为,因为
    Base
    没有虚拟析构函数。@PaulMcKenzie:当然,~Base()应该是虚拟的。刚写了几分钟就忘了这件事。@PaulMcKenzie:我认为在这种情况下不需要虚拟析构函数,因为使用了
    std::shared\u ptr
    @nosid:你为什么这么认为?@BenjaminLindley:这是未定义的行为,如果你通过基类指针删除派生类,如果基类具有非虚拟析构函数。但是,如果通过派生指针删除相同的派生类,则一切正常。使用
    std::make_shared
    就可以做到这一点。它将删除具有正确静态类型的对象,因此基类的析构函数是否为虚拟的并不重要。
    #include<iostream>
    #include<memory>
    
    struct Base
    {
        ~Base() {}
        virtual double operator()(double x) const = 0;
    };
    
    template<typename F, typename G> struct Compose;    
    
    struct A : public Base
    {
        virtual double operator()(double x) const {return x;}  //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc
        template <typename F>
        Compose<A,F> operator()(const F& f) const {return Compose<A,F>(*this,f);}
    };
    
    struct B : public Base
    {
        virtual double operator()(double x) const {return x*x;}  //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc
        template <typename F>
        Compose<B,F> operator()(const F& f) const {return Compose<B,F>(*this,f);}
    };
    
    struct C : public Base
    {
        virtual double operator()(double x) const {return x*x*x;}  //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc. 
        template <typename F>
        Compose<C,F> operator()(const F& f) const {return Compose<C,F>(*this,f);}
    };
    
    template<typename F, typename G>
    struct Compose : public Base
    {
          Compose(const F &_f, const G &_g) : f(_f), g(_g) {}
          F f;
          G g;
          virtual double operator()(double x) const {return f(g(x));}
    };
    
    int main()
    {
        double x=2.0;
        A a;
        B b;
        C c;
    
        std::shared_ptr<Base> ptrBase = std::make_shared<A>(A());
        std::shared_ptr<A> ptrA = std::make_shared<A>(a);
    
        std::cout<< a(x) <<std::endl;
        std::cout<< ptrBase->operator()(x) <<std::endl;
        std::cout<< ptrA->operator()(x) <<std::endl;
    
        std::cout<< b(a(x)) <<std::endl;
    
        std::cout<< c(b(a(x))) <<std::endl;
    
        std::cout<< a(c(b(a(x)))) <<std::endl;
        std::cout<< ptrA->operator()(c(b(ptrBase->operator()(x)))) <<std::endl;
    }
    
    2
    2
    2
    4
    64
    64
    64
    
    #include<iostream>
    #include<memory>
    #include<string>
    #include<map>
    
    
    struct Base
    {
        virtual ~Base() {}
        virtual double operator()(double x) const = 0;
        virtual std::string id() const = 0;
    };
    
    template<typename F, typename G> struct Compose;    
    
    template<typename T>
    struct Result
    {
        virtual ~Result() {}
        double get(double x) const
        {
        return mem.find(x)->second;
        }
    
        bool isSet(double x) const {it=mem.find(x); return it!=mem.end();}
    
        //get the previously found result by isSet(x)
        double get() const
        {
        return it->second;
        }
    protected:
        //the set function is const, as it works only on static variables
        //don't know whether it is the best idea, but it allows for a const operator() later...
        void set(double x, double y) const
        {
        mem.insert(std::make_pair(x,y));
        }
    private:
        static std::map<double, double> mem;
        static std::map<double, double>::const_iterator it;
    };
    
    
    template<typename T> std::map<double, double> Result<T>::mem;
    template<typename T> std::map<double, double>::const_iterator Result<T>::it=Result<T>::mem.begin();
    
    
    struct A : public Base, public Result<A>
    {
        virtual double operator()(double x) const
        {
        if(isSet(x))
        {
            return get();
        }
        else
        {
            double y=x;
            set(x,y);
            std::cout<<"setA   ";
            return y;
        }
        }
    
        template <typename F>
        Compose<A,F> operator()(const F& f) const {return Compose<A,F>(*this,f);}
        virtual std::string id() const {return "A";}
    };
    
    struct B : public Base, public Result<B>
    {
        virtual double operator()(double x) const
        {
        if(isSet(x))
        {
            return get();
        }
        else
        {
            double y=x*x;
            set(x,y);
            std::cout<<"setB   ";
            return y;
        }
        }
        template <typename F>
        Compose<B,F> operator()(const F& f) const {return Compose<B,F>(*this,f);}
        virtual std::string id() const {return "B";}
    };
    
    struct C : public Base, public Result<C>
    {
        virtual double operator()(double x) const
        {
        if(isSet(x))
        {
            return get();
        }
        else
        {
            double y=x*x*x;
            set(x,y);
            std::cout<<"setC   ";
            return y;
        }
        }
        template <typename F>
        Compose<C,F> operator()(const F& f) const {return Compose<C,F>(*this,f);}
        virtual std::string id() const {return "C";}
    };
    
    
    template<typename F, typename G>
    struct Compose : public Base, public Result<Compose<F,G> >
    {
          Compose(const F &_f, const G &_g) : f(_f), g(_g) {}
          F f;
          G g;
          virtual double operator()(double x) const
          {
          if(this->isSet(x))
          {
              return this->get();
          }
          else
          {
              double y=f(g(x));
              this->set(x,y);
              std::cout<<"set"<<this->id()<<"   ";
              return y;
          }
          }
          virtual std::string id() const {return f.id() + "(" + g.id() + ")";}
    };
    
    
    
    int main()
    {
        double x=2.0;
        A a;
        B b;
        C c;
    
        std::shared_ptr<Base> ptrBase = std::make_shared<A>(A());
        std::shared_ptr<A> ptrA = std::make_shared<A>(A());
    
        std::cout<<"-------------------------------"<<std::endl;
        std::cout<< a(x) <<std::endl;
        std::cout<<ptrBase->operator()(x) <<std::endl;
        std::cout<<ptrA->operator()(x) <<std::endl;
        std::cout<<"-------------------------------"<<std::endl;
        std::cout<<c(x)<<std::endl;
        std::cout<<C()(x)<<std::endl;
        std::cout<<C()(x)<<std::endl;
        std::cout<<"-------------------------------"<<std::endl;
    
        auto ba= b(a);
        std::cout<<ba(x) << std::endl;
    
        auto cba= c(ba);
        std::cout<<cba(x)<< std::endl;
    
        auto acba= a(cba);
        std::cout<<acba(x)<<std::endl;
    }
    
    -------------------------------
    setA   2
    2
    2
    -------------------------------
    setC   8
    8
    8
    -------------------------------
    setB   setB(A)   4
    setC(B(A))   64
    setA(C(B(A)))   64
    -------------------------------