您的位置:首页 > 编程语言 > C语言/C++

c++11实现l延迟调用(惰性求值)

2015-09-15 21:50 337 查看

惰性求值

惰性求值一般用于函数式编程语言中,在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在后面的某个时候求值。
可以利用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: