C++ C++;设计:函数结果的全局存储
考虑以下代码(根据gcc 4.7.2编译): 好的,简短问题的长前奏。这里会出现一些冗余计算,例如,A()(x)的结果会计算六次(一些通过对象,一些通过指针)。如何实现存储计算函数值的全局输出数组 我想到的一种方法应该是实现每个(组合)类唯一的函数C++ C++;设计:函数结果的全局存储,c++,c++11,memoization,C++,C++11,Memoization,考虑以下代码(根据gcc 4.7.2编译): 好的,简短问题的长前奏。这里会出现一些冗余计算,例如,A()(x)的结果会计算六次(一些通过对象,一些通过指针)。如何实现存储计算函数值的全局输出数组 我想到的一种方法应该是实现每个(组合)类唯一的函数std::string id(),外加一个全局std::map来存储结果,然后检查(当前)结果是否存在 你有没有看到其他更好的方法?提前谢谢 抱歉,伙计们,虽然有一些相似之处(单词“memorization”似乎在某种程度上触发了一种反射),但我真
std::string id()
,外加一个全局std::map
来存储结果,然后检查(当前)结果是否存在
你有没有看到其他更好的方法?提前谢谢
抱歉,伙计们,虽然有一些相似之处(单词“memorization”似乎在某种程度上触发了一种反射),但我真的不明白为什么这应该是重复的。。。但我愿意讨论 在我看来,上述情况比链接线程中的情况要复杂得多(例如,它不仅仅是一个斐波那契函数)。此外,据我所知,高亮显示的memonization类将以不同的方式处理对象和指针(至少在不进行进一步编辑的情况下)。我的意图是得出一种模式,其中每个结果只计算一次,并考虑如何调用它 到目前为止,我一直在使用CRTP的静态结果类,这导致了以下代码(使用GCC4.7.2编译): 好的,这里需要注意一些事情:
编辑2:帮助自己是一件好事,现在的代码工作,因为我一直在寻找。我已经在上面的帖子中更新了它 变化:
现在我不再自言自语了。欢迎评论。谢谢,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
-------------------------------