惰性求值
惰性求值一般用于函数式编程语言中,在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在后面的某个时候求值。
可以利用c++11中的std::function, lambda表达式以及c++11实现的Optional来实现lazy。其中,std::function用来保存传入的函数,不马上执行,而是延迟到后面需要使用值的时候才执行,函数的返回值被放到一个Optional对象中(可以更方便的知道是否求值完毕,使用起来更方便)。通过optional对象可以知道是否已经求值,当发现已经求值的时候直接返回之前计算的结果,起到了缓存的作用。
c++11实现延迟(惰性)求值【代码均参考网上】
(1) Optional.hpp
//Optional.hpp 实现 Optional #include<type_traits> #include<iostream> #include<string> #include<map> using namespace std; template<typename T> class Optional { using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type; public: Optional() : m_hasInit(false) {} Optional(const T& v) { Create(v); } Optional(T&& v) : m_hasInit(false) { Create(std::move(v)); } ~Optional() { Destroy(); } Optional(const Optional& other) : m_hasInit(false) { if (other.IsInit()) Assign(other); } Optional(Optional&& other) : m_hasInit(false) { if (other.IsInit()) { Assign(std::move(other)); other.Destroy(); } } Optional& operator=(Optional &&other) { Assign(std::move(other)); return *this; } Optional& operator=(const Optional &other) { Assign(other); return *this; } template<class... Args> void emplace(Args&&... args) { Destroy(); Create(std::forward<Args>(args)...); } bool IsInit() const { return m_hasInit; } explicit operator bool() const { return IsInit(); } T& operator*() { if (IsInit()) { return *((T*)(&m_data)); } throw std::logic_error("is not init"); } T const& operator*() const { if (IsInit()) { return *((T*)(&m_data)); } throw std::logic_error("is not init"); } bool operator == (const Optional<T>& rhs) const { return (!bool(*this)) != (!rhs) ? false : (!bool(*this) ? true : (*(*this)) == (*rhs)); } bool operator < (const Optional<T>& rhs) const { return !rhs ? false : (!bool(*this) ? true : (*(*this) < (*rhs))); } bool operator != (const Optional<T>& rhs) { return !(*this == (rhs)); } private: template<class... Args> void Create(Args&&... args) { new (&m_data) T(std::forward<Args> (args)...); m_hasInit = true; } void Destroy() { if (m_hasInit) { m_hasInit = false; ((T*)(&m_data))->~T(); } } void Assign(const Optional& other) { if (other.IsInit()) { Copy(other.m_data); m_hasInit = true; } else { Destroy(); } } void Assign(Optional&& other) { if (other.IsInit()) { Move(std::move(other.m_data)); m_hasInit = true; other.Destroy(); } else { Destroy(); } } void Move(data_t&& val) { Destroy(); new (&m_data) T(std::move(*((T*) (&val)))); } void Copy(const data_t& val) { Destroy(); new (&m_data) T(*((T*)(&val))); } private: bool m_hasInit; data_t m_data; };
(2) Lazy.cpp
#include"Optional.hpp" #include<memory> #include<functional> template<typename T> struct Lazy{ Lazy(){}; //保存需要延迟执行的函数 template<typename Func, typename ...Args> Lazy(Func& f, Args&&... args){ //给出需要调用的函数和参数,封装起来。等待之后被调用 m_func = [&f, &args...]{return f(args...); }; } //延迟执行,将结果放到optional中缓存起来,下次不用重新计算可以直接得到结果 T& Value(){ if (!m_value.IsInit()){ m_value = m_func(); } return *m_value; } bool IsValueCreated()const{ return m_value.IsInit(); } private: std::function<T()> m_func; //返回值类型为T的无参可调用对象 m_func Optional<T> m_value; }; //定义一个模板函数,返回值类型为 Lazy template<class Func, typename... Args> Lazy<typename std::result_of<Func(Args...)>::type> lazy(Func&& fun, Args&& ...args){ return Lazy<typename std::result_of<Func(Args...)>::type>(std::forward<Func>(fun), std::forward<Args>(args)...); } struct BigObject{ BigObject(){ cout << "lazy load big object" << endl; } }; struct MyStruct{ MyStruct(){ m_obj = lazy([]{return std::make_shared<BigObject>(); }); } void Load(){ m_obj.Value(); } Lazy<std::shared_ptr<BigObject>> m_obj; }; int Foo(int x){ return x * 2; } void TestLazy(){ //带参数的普通函数 int y = 4; auto lazyer1 = lazy(Foo, y); cout << lazyer1.Value() << endl; //不带参数的lambda Lazy<int> lazyer2 = lazy([]{return 12; }); cout << lazyer2.Value() << endl; //带参数的function std::function<int(int)> f = [](int x){return x + 3; }; auto lazyer3 = lazy(f, 3); cout << lazyer3.Value() << endl; //延迟加载大对象 MyStruct t; t.Load(); } int main(){ TestLazy(); return 0; }