C++11 让程序更简洁、更优雅

可调用对象

  1. 是一个函数指针
  2. 是一个具有operator()成员函数的类对象(仿函数)
  3. 是一个可被装换为函数指针的类对象
  4. 是一个类的成员(函数)指针
void func()
{ } struct Foo
{
void operator()(void)
{ }
}; struct Bar
{
using fr_t = void(*)(void);
static void func(void)
{
} operator fr_t(void)
{
return func;
}
}; struct A
{
int a_;
void mem_func(void)
{
}
}; int main()
{
void(*func_ptr)(void) = &func; //函数指针
func_ptr(); Foo foo; //仿函数
foo(); Bar bar;
bar(); //可被转换为函数指针的类的对象 void(A::*mem_func_ptr)(void) = &A::mem_func; //类成员函数指针
int A::*mem_obj_ptr = &A::a_; //类成员指针 A aa;
(aa.*mem_func_ptr)();
aa.*mem_obj_ptr = 123; return 0;
}

std::function

  std::function是可调用对象的包装器,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。

#include <iostream>
#include <functional> using namespace std; void func(void)
{
std::cout << __FUNCTION__ << std::endl;
} class Foo
{
public:
static int foo_func(int a)
{
std::cout << __FUNCTION__ << std::endl;
return a;
}
}; class Bar
{
public:
void operator()(void)
{
std::cout << __FUNCTION__ << std::endl;
}
}; class A
{
std::function<void()> callback_;
public:
A(const std::function<void()>& f):callback_(f)
{ } void notify(void)
{
callback_();
}
}; void call_when_even(int x, const std::function<void(int)>& f)
{
if(!(x & 1))
{
f(x);
}
} void output(int x)
{
std::cout << x << " ";
} int main()
{
std::function<void(void)> fr1 = func; //普通函数
fr1(); std::function<int(int)> fr2 = Foo::foo_func; //类的静态成员函数
std::cout << fr2(123) << std::endl; Bar bar; //仿函数
fr1 = bar;
fr1(); A aa(bar);
aa.notify(); for (size_t i = 0; i < 10; i++)
{
call_when_even(i, output);
}
std::cout << std::endl; return 0;
}

std::bind

  std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候

  1. 将可调用对象与其参数一起绑定成一个仿函数
  2. 将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数
class B
{
public:
std::string name_;
void output(int x, int y)
{
std::cout << x << " " << y << std::endl;
}
}; int main()
{
B b;
std::function<void(int,int)> fr = std::bind(&B::output, &b, std::placeholders::_1, std::placeholders::_2);
fr(1,2); std::function<std::string&(void)> fr_s = std::bind(&B::name_, &b);
fr_s() = "hello"; std::cout << b.name_ << std::endl; return 0;
}

后置返回类型

template <typename T, typename U>
//decltype(t+u) add(T t, U u) //C++的返回值是前置语法,返回值定义的时候参数还未定义
//decltype(T()+U()) add(T t, U u) //通过构造函数完成推导,如果一个类没有无参构造函数,这个地方就会报错
//decltype( (*(T*)0) + (*(U*)0) ) add(T t, U u) //OK,但不够优雅
auto add(T t, U u) -> decltype(t+u)
{
return (t + u);
}

模板别名

typedef std::map<std::string, int> map_s_i;
map_s_i mymap1{std::make_pair("first",1)}; typedef std::map<std::string, std::string> map_s_s;
map_s_s mymap2{ std::make_pair("second","second") }; //需求 固定以std::string最为map的key,它可以映射到不同的类型(如int、long、string等) //在c++98|C++03, 比较猥琐写法
template<typename T>
struct mymap
{
typedef std::map<std::string, T> type;
};
mymap<int>::type mymap3;
mymap<double>::type mymap3; //c++11
template <typename T>
using mymapt = std::map<std::string, T>;
mymapt<int> mymap4; //这个地方主要用到了using,在c++11中,使用using基本可以替代typedef
using funcType = int(*)(int,int); template<typename T>
using funcT = int(*)(T,T); int func_int(int n1,int n2)
{
return n1+n2;
} funcT<int> func_i = func_int;
func_i(1,2);

函数模板默认参数

  c++11前,只能为类模板提供默认模板参数,c++11后可以为函数模板提供默认参数

template<typename T=std::string,int size = 10>
class myarray
{
private:
T arr[size];
public:
void myfunc();
} class tc
{
public:
tc() { std::cout << "构造函数" << std::endl; }
tc(const tc& t) { std::cout << "拷贝构造" << std::endl; }
int operator()(int v1, int v2)const
{
return v1 + v2;
}
}; template<typename T, typename F = tc>
T test(const T& i, const T& j, F funcpoint = F())
{
return funcpoint(i, j);
} template <typename T = int, typename U>
auto func(U val)->decltype(val)
{
std::cout << typeid(val).name() << std::endl;
return val;
} //在调用函数模板时,若显示指定模板的参数,参数的填充顺序是从右到左
func(123);
// T << std::string << U << 123.363
func<std::string>(123.363);

tuple

  1. tuple 构造的tuple对象所保存的是构造实参的拷贝
  2. make_tuple: 构造tuple对象所保存的是构造实参的拷贝
  3. tie: 通过tie构造的tuple对象,保存构造实参的可写引用
  4. forward_as_tuple:通过forward_as_tuple构造的tuple对象,保存构造实参的原始引用,左值使用左值引用,右值使用右值引用
template<class Tuple, std::size_t N>
struct TuplePrinter
{
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N-1>::print(t);
std::cout << " " << std::get<N-1>(t);
}
}; template<class Tuple>
struct TuplePrinter<Tuple, 1>
{
static void print(const Tuple& t)
{
std::cout << std::get<0>(t);
}
}; template<class... Args>
void print(const std::tuple<Args...>& t)
{
std::cout << "( ";
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
std::cout << " )\n";
} void show()
{
std::cout << std::endl;
} template <class T, class... Args>
void show(const T& t, const Args &... args)
{
std::cout << t << " ";
show(args...);
} int main()
{
int age = 20;
float height = 170.6;
std::string name = "小马"; std::cout << "----- tuple() -----" << std::endl;
// tuple构造函数
std::tuple<std::string, int, float> tp1(name, age, height);
// 获取元素的值
print(tp1);
// 修改元素的值
std::get<0>(tp1) = "小云";
std::get<1>(tp1) = 40;
std::get<2>(tp1) = 16.8;
// 获取元素的值
print(tp1);
// 获取变量的值; 通过结果发现,tuple构造函数构造的对象保存的是构造实参的拷贝
show("(", name, age, height, ")"); std::cout << "----- make_tuple -----" << std::endl;
// 通过make_tuple构造tuple对象
// auto tp2 = std::make_tuple(name, age, height);
auto tp2 = std::make_tuple("hello", 1, 2.0); //等价于上面的
// 获取元素的值
print(tp2);
// 修改元素的值
std::get<0>(tp2) = "小李";
std::get<1>(tp2) = 35;
std::get<2>(tp2) = 18.0;
// 获取元素的值
print(tp2);
// 获取变量的值; 通过结果发现,make_tuple构造的对象保存的也是构造实参的拷贝
show("(", name, age, height, ")"); std::cout << "----- tie -----" << std::endl;
// 通过tie构造tuple对象
auto tp3 = std::tie(name, age, height);
// auto tp3 = std::tie("hello", 2, 2);
// 获取元素的值
print(tp3);
// 修改元素的值
std::get<0>(tp3) = "小李";
std::get<1>(tp3) = 35;
std::get<2>(tp3) = 18.0;
// 获取元素的值
print(tp3);
// 获取变量的值; 通过结果发现,成功修改了构造实参
show("(", name, age, height, ")"); std::cout << "----- tie parser tuple-----" << std::endl;
// 通过tie解析tuple对象
auto tp4 = std::make_tuple("关羽", 30, 1.85);
tie(name, age, height) = tp4;
show("(", name, age, height, ")"); std::cout << "----- forward_as_tuple lvalue-----" << std::endl;
auto tp5 = forward_as_tuple(name, age, height);
// 获取元素的值
print(tp4);
// 修改元素的值,get得到的是左值引用
std::get<0>(tp5) = "小王";
std::get<1>(tp5) = 35;
std::get<2>(tp5) = 18.0;
// 获取元素的值
print(tp4);
// 获取变量的值; 通过结果发现,成功修改了构造实参
show("(", name, age, height, ")"); std::cout << "----- forward_as_tuple rvalue-----" << std::endl;
auto tp6 = std::forward_as_tuple("小赵", 30, 1.85);
// 获取元素的值
print(tp6);
// 修改元素的值,这是get得到的是一个右值引用,无法修改
// std::get<0>(tp6) = "小王";
// std::get<1>(tp6) = 35;
// std::get<2>(tp6) = 18.0; return 0;
}

内容来源于:深入应用C++11 代码优化与工程级应用

学习《深入应用c++11》1的更多相关文章

  1. Kafka 学习笔记之 Kafka0.11之console-producer/console-consumer

    Kafka 学习笔记之 Kafka0.11之console-producer/console-consumer: 启动Zookeeper 启动Kafka0.11 创建一个新的Topic: ./kafk ...

  2. 学习Python编程的11个资源

    用 Python 写代码并不难,事实上,它一直以来都是被声称为最容易学习的编程语言.如果你正打算学习 web 开发,Python 是一个不错的选择,甚至你想学游戏开发也可 以从 Python 开始,因 ...

  3. 学习Python编程的11个精品资源

    本文由 伯乐在线 - atupal 翻译自 Alex Ivanovs.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. 用 Python 写代码并不难,事实上,它一直以来都是被声称为最容易学习的编程 ...

  4. 201771010126 王燕《面向对象程序设计(Java)》第十四周学习总结(测试程序11)

    实验十四  Swing图形界面组件 理论部分: 不使用布局管理器 有时候可能不想使用任何布局管理器,而只 是想把组件放在一个固定的位置上.下面是将一 个组件定位到某个绝对定位的步骤: 1)将布局管理器 ...

  5. 学习激动人心的C++ 11

    1->创建7个Thread,跑个非常大的循环.观察CPU void func(string &name) { ;i<0xFFFFFFFF;i++) { //cout << ...

  6. java系列:《java核心技术 卷1》学习笔记,chapter 11 调试技巧

    11. 6 调试技巧 1)一个不太为人所知却非常有效的技巧是在每个类中放一个main方法,这样就可以对每个类进行单元测试.这个方法可以保留,因为在java虚拟机只调用启动类的main方法. 2)   ...

  7. 201521123016 《Java学习笔记》 第11周学习总结

    1. 本周学习总结 2. 书面作业 本次PTA作业题集多线程 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问, ...

  8. 吴裕雄 python深度学习与实践(11)

    import numpy as np from matplotlib import pyplot as plt A = np.array([[5],[4]]) C = np.array([[4],[6 ...

  9. 《从零开始学Swift》学习笔记(Day 11)——数据类型那些事儿?

    原创文章,欢迎转载.转载请注明:关东升的博客        在我们学习语言时都会学到这种语言的数据类型,在Swift中数据类型有那些呢?整型.浮点型.布尔型.字符.字符串这些类型是一定有的,其中集合. ...

  10. 学习动态性能表(11)v$latch$v$latch_children

    学习动态性能表 第十一篇-(1)-V$LATCH  2007.6.7 Oracle Rdbms应用了各种不同类型的锁定机制,latch即是其中的一种.Latch是用于保护SGA区中共享数据结构的一种串 ...

随机推荐

  1. react / config\webpack.config.js 编译后去掉map 减小体积 shouldUseSourceMap = false

    react / config\webpack.config.js 编译后去掉map 减小体积 shouldUseSourceMap = false

  2. 关于Addressable的疑问

    1)关于Addressable的疑问2)Addressable如何进行热更新3)如何设置SceneView相机的Shader变量4)Activity默认为SingleTask的原因5)关于Resour ...

  3. strongsan基本用法

    0x01 安装 ====> CentOS RPM安装 下载:https://pkgs.org/download/strongswanwget http://download-ib01.fedor ...

  4. Python程序设计试验报告一: 熟悉IDLE和在线编程平台

    安徽工程大学 Python程序设计 实验报告                                                                  班级   物流192   ...

  5. Jmeter Agent自动化

    1.打开菜单栏-附件-系统工具-任务计划程序,新建PerformanceTest目录. 2.在PerformanceTest目录下新建一个基本任务. 3.完成. 这样,当我们在使用Jmeter进行分布 ...

  6. Multi-batch TMT reveals false positives, batch effects and missing values(解读人:胡丹丹)

    文献名:Multi-batch TMT reveals false positives, batch effects and missing values (多批次TMT定量方法中对假阳性率,批次效应 ...

  7. 第二周Java实验作业

    实验二 Java基本程序设计(1) 实验时间 2018-9-6 1.实验目的与要求 (1)进一步熟悉命令行和IDE两种方式下java程序开发的基本步骤: (2)掌握Eclipse集成开发环境下导入Ja ...

  8. 灵感来袭,基于Redis的分布式延迟队列

    延迟队列 延迟队列,也就是一定时间之后将消息体放入队列,然后消费者才能正常消费.比如1分钟之后发送短信,发送邮件,检测数据状态等. Redisson Delayed Queue 如果你项目中使用了re ...

  9. 从数据结构分析mysql为何使用B+tree

    理解mysql为何选择升级版的二叉树,就需要对各种常用的二叉树进行对比.B+Tree是一种特殊的二叉树,本质上也算二叉树.自然会满足二叉树的一般特性. 比如,比节点数据大的在右边,节点数据小的在左边. ...

  10. 李宏毅老师机器学习课程笔记_ML Lecture 0-2: Why we need to learn machine learning?

    引言: 最近开始学习"机器学习",早就听说祖国宝岛的李宏毅老师的大名,一直没有时间看他的系列课程.今天听了一课,感觉非常棒,通俗易懂,而又能够抓住重点,中间还能加上一些很有趣的例子 ...