マクロとラムダを組み合わせてこの効果を作成できます
あなたは怠惰なタイプを持つことができます
template<class T>
class lazy {
...
}
そして、ラムダを使用してこれらのいずれかを作成するLAZYラッパーを作成できます
#define LAZY(E) my_lazy_type<decltype((E))>([&](){ return E; })
my_lazy_type に必要なのは、std::function を受け入れるコンストラクターと、これを評価して返す operator() のオーバーロードだけです。各評価で、既に計算された値を返すだけのサンクにサンクを置き換えることができるため、一度だけ計算されます。
編集:これは私が話していることの例です。ただし、これは完璧な例ではないことを指摘しておきます。それは、そもそもこれをすべて行う目的を完全に無効にする可能性のある怠惰な側で値によってたくさんのものを渡します。const の場合にサンクをメモできるようにする必要があるため、この内部でミュータブルを使用します。これは多くの点で改善される可能性がありますが、概念の適切な証明です。
#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;
}