だから私は遅延評価に関する質問に答えていました (ここで、私の答えはその場合にはやり過ぎですが、アイデアは興味深いようです)、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;
}
デザインで気になった点をいくつか。
- decltype には奇妙な規則がいくつかあります。私の decltype の使用法には落とし穴がありますか? LAZY マクロの E の周りに余分な括弧を追加して、vec[10] と同じように、単一の名前が公平に扱われるようにしました。私が説明していない他のものはありますか?
- 私の例では、間接的な層がたくさんあります。これは避けられそうです。
- これは結果を正しく記憶しているので、遅延値を参照するものや数に関係なく、一度だけ評価されます(これはかなり自信がありますが、遅延評価と大量の共有ポインターがループを投げている可能性があります)
あなたの考えは何ですか?