您可以混合使用宏和 lambda 来创建这种效果
你可以有一个类型,懒惰
template<class T>
class lazy {
...
}
然后你可以有一个 LAZY 包装器,它使用 lambda 创建其中一个
#define LAZY(E) my_lazy_type<decltype((E))>([&](){ return E; })
所有 my_lazy_type 需要的是一个接受 std::function 的构造函数,以及计算并返回 this 的 operator() 的重载。在每次评估中,您可以将 thunk 替换为仅返回已计算值的 thunk,因此它只会被计算一次。
编辑:这是我正在谈论的一个例子。然而,我想指出,这不是一个完美的例子。它在懒惰的人身上传递了一堆价值,这可能会完全违背首先做这一切的目的。它在其中使用 mutable ,因为我需要能够在 const 情况下记住 thunk。这可以在很多方面进行改进,但它是一个不错的概念证明。
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#define LAZY(E) lazy<decltype((E))>{[&](){ return E; }}
template<class T>
class lazy {
private:
struct wrapper {
std::function<T()> thunk;
wrapper(std::function<T()>&& x)
: thunk(std::move(x)) {}
wrapper(const std::function<T()>& x)
: thunk(x) {}
};
//anytime I see mutable, I fill a bit odd
//this seems to be warented here however
mutable std::shared_ptr<wrapper> thunk_ptr;
public:
lazy(std::function<T()>&& x)
: thunk_ptr(std::make_shared<wrapper>(std::move(x))) {}
T operator()() const {
T val = thunk_ptr->thunk();
thunk_ptr->thunk = [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";
log(LAZY(hello + ", " + world + "!"));
return 0;
}