1. optional类的实现

(1)optional的功能

  ①optional<T>的内部存储空间可能存储了T类型的值,也可能没有。只有当optional被T初始化之后,这个optional才是有效的。否则是无效的。它实现了未初始化的概念

  ②optional可以用于解决函数返回无效值的问题。当函数返回一个未初始化的Optional对象时,表明函数正确执行了,只是结果不是有用的值。

  ③举例:optional<int> op; //未被初始化。 optional<int> op = 1; //初始化。

(2)实现细节

  ①由于optional<T>需要容纳T的值,所以需要一个缓冲区来保存它,但考虑到内存对齐,需要将T指定在对齐的位置上。可以通过std::alignment_of <T>::value来获取T的内存对齐大小。并通过std::aligned_storage<sizeof(T), aligned(T)>来定义T的内存对齐类型(该模板的本质就重新定义T经对齐后的一种新类型)。

template<unsigned size, unsigned alignment>
struct aligned_storage
{
using type = struct { alignas(alignment) unsigned char data[size]; };
};

  ②std::aligned_storage一般和placement_new结合使用(见Optional类的create函数),用于初始化由std::aligned_storage定义的一片内存空间。

  ③增加一个m_hasInit标记来记录T空间是否己经初始化。

【编程实验】Optional类的实现

//Optional.hpp

#ifndef _OPTIONAL_H_
#define _OPTIONAL_H_ #include <type_traits>
#include <utility> //for std::forward
#include <stdexcept> template <typename T>
class Optional
{
//std::alignment_of<T>::value获取T的内存对齐大小,std::aligned_storage将T重定义为对齐后的类型
using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
private:
data_t m_data; //内存对齐缓冲区
bool m_hasInit; //是否己经初始化
private:
//调用placement_new来创建T对象
template<class... Args>
void create(Args... args) //可以接收左右值
{
new (&m_data) T(std::forward<Args>(args)...); //调用T的构造函数来初始化m_data空间
m_hasInit = true;
} //销毁缓冲区的对象
void destroy()
{
if(m_hasInit){
m_hasInit = false;
((T*)(&m_data))->~T(); //调用T的析构函数
}
} //缓冲区的拷贝
void copy(const data_t& val)
{
destroy();
new (&m_data) T(*((T*)(&val)));
} //缓冲区的移动
void move(data_t&& val)
{
destroy(); //调用T的移动构造函数进行移动
new (&m_data) T(std::move(*((T*)(&val))));
} //Optional赋值操作(左值版本)
void assign(const Optional& other)
{
if(other.isInit()){
copy(other.m_data);
m_hasInit = true;
}else{
destroy();
}
} //Optional赋值操作(右值版本)
void assign(Optional&& other)
{
if(other.isInit()){
move(std::move(other.m_data));
m_hasInit = true; other.destroy(); //other失去资源控制权
}else{
destroy();
}
} public:
Optional():m_hasInit(false){};
Optional(const T& v)
{
create(v);
} Optional(T&& v) : m_hasInit(false)
{
create(std::move(v));
} 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();
}
} //根据参数创建对象,如emplace(1,2);
template<class ...Args>
void emplace(Args&& ...args)
{
destroy();
create(std::forward<Args>(args)...);
} Optional& operator=(const Optional& other)
{
assign(other);
return *this;
} Optional& operator=(Optional&& other)
{
assign(std::move(other));
return *this;
} explicit operator bool() const //类型转换函数,如if(op)
{
return isInit();
} T& operator*()
{
if(isInit()){
return *((T*)(&m_data));
} throw std::logic_error{"try to get data in a Optional which is not initialized"};
} const T& operator*() const
{
if(isInit()){
return *((T*)(&m_data));
} throw std::logic_error{"try to get data in a Optional which is not initialized"};
} T* operator->()
{
return &operator*();
} const T* operator->() const
{
return &operator*();
} bool operator==(const Optional<T>& rhs) const
{
bool bInit = bool(*this);
return ( !bInit != (!rhs) ? //*this和rhs中一个初始化,一个未初始化
false :
!bInit ? true : (*(*this) == (*rhs)) //两者都未初始化,返回true
//两者都初始化时,比较两个T对象是否相等
);
} bool operator<(const Optional<T>& rhs) const
{
bool bInit = bool(*this);
return !rhs ? false : (!bInit ? true : (*(*this) < (*rhs)));
} bool operator!=(const Optional<T>& rhs) const
{
return !(*this == rhs);
} bool isInit() const {return m_hasInit;} ~Optional()
{
destroy();
} }; #endif

//main.cpp

#include "Optional.hpp"
#include <iostream> using namespace std; struct Test
{
Test() : m_a(), m_b(){}
Test(int a, int b) : m_a(a), m_b(b){} int m_a;
int m_b;
void show()
{
cout << "a = "<< m_a << ", b = " << m_b << endl;
}
}; void TestOptional()
{
const Optional<string> a("ok");
Optional<string> b("ok");
Optional<string> c("aa");
Optional<string> d = b;
Optional<string> e; cout << (e<b) << endl; //true
cout << (b==d) << endl; //true
cout << *c << endl;
//cout << *e << endl; //error Optional<Test> op;
op.emplace(, );
(*op).show(); Test t;
if(op) //判断op是否被初始化
t = *op;
t.show(); op.emplace(, );
t = *op;
t.show();
} int main()
{
TestOptional();
return ;
} /*输出结果:
e:\Study\C++11\23>g++ -std=c++11 test.cpp
e:\Study\C++11\23>a.exe
1
1
aa
a = 1, b = 2
a = 1, b = 2
a = 3, b = 4
*/

2. 惰性求值:Lazy类的实现

(1)Lazy类的功能

  ①惰性求值一般用于函数式编程语言中。

  ②可实现函数的延迟调用,函数参数被绑定后并不立即调用,而是在以后的某个时候调用。

  ③可实现大对象数据的延迟加载。如当初始化某个对象时,该对象引用了一个大对象,但很多时候并不马上获取该对象的数据,就可以延迟加载这个大对象。

(2)实现细节

  ①借助lambda表达式,将函数封装到lambda表达式中,而不是马上求值,在需要的时候再调用lambda表达式去求值

  ②std::function用于保存传入的函数,并延迟到后面需要使用值的时候才执行,函数的返回值放到一个Optional对象中。Optional对象是否被初始化,来判断大对象是否己加载。

  ③辅助函数lazy的作用是方便使用Lazy类, Lazy<T>中的T用来表示返回值类型大对象的类型这也是被封装的函数返回值类型,可利用std::result_of来获取该返回值类型。

【编程实验】Lazy类的实现

//Lazy.hpp

#ifndef _LAZY_H_
#define _LAZY_H_ #include "Optional.hpp"
#include <functional>
#include <type_traits>
#include <utility> //for std::forward template<typename T>
struct Lazy
{
private:
Optional<T> m_value;
std::function<T()> m_func;
public:
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();
}
}; //辅助函数,简化Lazy的调用
template<class Func, typename... Args>
Lazy<typename std::result_of<Func(Args...)>::type> //返回值类型Lazy<T>
lazy(Func&& fun, Args&&... args)
{
using ret_type_t = typename std::result_of<Func(Args...)>::type;
return Lazy<ret_type_t>(std::forward<Func>(fun), std::forward<Args>(args)...);
} #endif // _LAZY_H_

//main.cpp

#include "Lazy.hpp"
#include <iostream>
#include <memory> //for std::shared_ptr using namespace std; struct BigObject
{
BigObject()
{
cout << "lazy load big object..." << endl;
}
}; struct Test
{
private:
Lazy<std::shared_ptr<BigObject>> m_obj;
public:
Test()
{
m_obj = lazy([]{return std::make_shared<BigObject>();});
} void load()
{
m_obj.value();
}
}; int Foo(int x)
{
return x * ;
} void TestLazy()
{
//带参数的普通函数
int a = ;
auto lazy1 = lazy(Foo, a);
cout << lazy1.value() << endl; //8 //不带参数的lambda表达式
Lazy<int> lazy2 = lazy([]{return ;});
cout << lazy2.value() << endl; //12 //带参的function
std::function<int(int)> f = [](int x){return x + ;};
auto lazy3 = lazy(f, a);
cout << lazy3.value() << endl; //7 //延迟加载大对象
Test t;
t.load(); //lazy load big object...
} int main()
{
TestLazy();
return ;
}

第23课 可变参数模板(4)_Optional和Lazy类的实现的更多相关文章

  1. 第27课 可变参数模板(8)_TupleHelper

    1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...

  2. 第26课 可变参数模板(7)_any和variant类的实现

    1. any类的实现 (1)any类: ①是一个特殊的,只能容纳一个元素的容器,它可以擦除类型,可以将何任类型的值赋值给它. ②使用时,需要根据实际类型将any对象转换为实际的对象. (2)实现any ...

  3. 第25课 可变参数模板(6)_function_traits和ScopeGuard的实现

    1. function_traits (1)function_traits的作用:获取函数的实际类型.返回值类型.参数个数和具体类型等.它能获取所有函数语义类型信息.可以获取普通函数.函数指针.std ...

  4. 第24课 可变参数模板(5)_DllHelper和lambda链式调用

    1. dll帮助类 (1)dll的动态链接 ①传统的调用方式:先调用LoadLibrary来加载dll,再定义函数指针类型,接着调用GetProcAddress获取函数地址.然后通过函数指针调用函数, ...

  5. C++反射机制:可变参数模板实现C++反射

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在Github ...

  6. C++ 0x 使用可变参数模板类 实现 C# 的委托机制

    #ifndef _ZTC_DELEGATE_H_ #define _ZTC_DELEGATE_H_ #include <vector> #include <functional> ...

  7. c++11 可变参数模板类

    c++11 可变参数模板类 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #inc ...

  8. c++11 可变参数模板函数

    c++11 可变参数模板函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #in ...

  9. C++反射机制:可变参数模板实现C++反射(使用C++11的新特性--可变模版参数,只根据类的名字(字符串)创建类的实例。在Nebula高性能网络框架中大量应用)

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在码云的仓库地 ...

随机推荐

  1. Component(组件)

    1.Component是一个模板的控制类用于处理应用和逻辑页面的视图部分. 2.Component时Angular2应用最基础的建筑砖块. 3.任何一个Component都是NgModule的一部分, ...

  2. 笨办法29IF语句

    people = 20 cats = 30 dogs = 15 if people < cats: print "Too many cats! The world is doomed! ...

  3. Saiku免登录嵌入其他系统使用(十一)

    Saiku免登录嵌入其他系统使用 Saiku可通过iframe嵌入其他系统使用,但是正常情况下都需要先登录系统,然后还需要登录saiku,最后才能访问saiku中的数据 下面来讲解一下如何使Saiku ...

  4. 对聊天室项目的NABCD的分析

    NABCD需求分析: 需求(N):我们的项目是制作一个局域网内的聊天室软件,为了解决一个公司或者小团体内小范围的局域的简单通讯问题,我们针对的需求是简单与安全. 做法(A):用Java来实现一个C/S ...

  5. [Oracle][RAC]Oracle RAC环境里打OCW上的个别Patch,然后Rollback,发现OCW也被Rollback掉了

    对于Oracle RAC来说,存在着DB层面的Patch,也存在着GI层面的Patch. 本文介绍的是,GI层面,打Patch----> rollback 的动作之后,原来的OCW被Rollba ...

  6. 查看shell 命令 路径

    type [root@web01 ~]# type mount mount is /bin/mount which [root@web01 ~]# type ifconfig ifconfig is ...

  7. 网络性能测试工具-Iperf

    一.简单介绍 Iperf是一个网络性能测试工具,Iperf可以测试TCP和UDP带宽质量,Iperf可以测量最大TCP带宽,具有多种参数和UDP特性.Iperf可以报告带宽,延迟抖动和数据包丢失.利用 ...

  8. 关于itext生成pdf的新的demo(包含简单的提取txt文件的内容 和xml内容转化为pdf)

    一.用的iText版本为7.0.2版本,maven的配置如下: <dependencies> <!-- always needed --> <dependency> ...

  9. IC卡插入与触点激活时序

    当IC卡插入接口设备时,终端应确保其所有触点处于低电平状态: 当IC卡插入接口设备后,触点须按如下方式激活: 要点: 终端必须在整个激活时序中保持RST为低电平状态: 触点物理接触之后,应在IO或CL ...

  10. OpenCV实现彩色图像轮廓 换背景颜色

    转摘请注明:https://i.cnblogs.com/EditPosts.aspx?opt=1 有时候我们需要不一样颜色的证件照,下面就用OpenCV来实现证件照的蓝底.红底等换颜色: 代码如下: ...