所以我回答了一个关于延迟评估的问题(here,对于这种情况,我的回答是过分的,但是这个想法似乎很有趣),这让我思考了如何在C++中完成延迟评估。我想出了一种方法,但是我不确定所有的陷阱。还有其他方法可以实现惰性评估吗?怎么做?有哪些陷阱以及此设计和其他设计?
这是我的主意:
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#define LAZY(E) lazy<decltype((E))>{[&](){ return E; }}
template<class T>
class lazy {
private:
typedef std::function<std::shared_ptr<T>()> thunk_type;
mutable std::shared_ptr<thunk_type> thunk_ptr;
public:
lazy(const std::function<T()>& x)
: thunk_ptr(
std::make_shared<thunk_type>([x](){
return std::make_shared<T>(x());
})) {}
const T& operator()() const {
std::shared_ptr<T> val = (*thunk_ptr)();
*thunk_ptr = [val](){ return val; };
return *val;
}
T& operator()() {
std::shared_ptr<T> val = (*thunk_ptr)();
*thunk_ptr = [val](){ return val; };
return *val;
}
};
void log(const lazy<std::string>& msg) {
std::cout << msg() << std::endl;
}
int main() {
std::string hello = "hello";
std::string world = "world";
auto x = LAZY((std::cout << "I was evaluated!\n", hello + ", " + world + "!"));
log(x);
log(x);
log(x);
log(x);
return 0;
}
我在设计中担心的一些事情。
你怎么认为?
最佳答案
thunk_type
并将其引用作为单独的对象。现在,lazy<T>
的副本不会从原产地评估中获得任何 yield 。但是在这种情况下,您将获得其他间接访问。 考虑下一个修改:
template<typename F>
lazy(const F& x) :
thunk_ptr([&x,&this](){
T val = (*x)();
thunk_ptr = [val]() { return val; };
return val;
})
{}
或者替代实现可能看起来像:
template<typename F>
auto memo(const F &x) -> std::function<const decltype(x()) &()> {
typedef decltype(x()) return_type;
typedef std::function<const return_type &()> thunk_type;
auto thunk_ptr = std::make_shared<thunk_type>();
auto *thunk_cptr = thunk_ptr.get();
// note that this lambda is called only from scope which holds thunk_ptr
*thunk_ptr = [thunk_cptr, &x]() {
auto val = std::move(x());
auto &thunk = *thunk_cptr;
thunk = [val]() { return val; };
// at this moment we can't refer to catched vars
return thunk();
};
return [thunk_ptr]() { return (*thunk_ptr)(); };
};
关于c++ - 一种在C++中实现惰性评估的方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16701108/