《深入应用C++11》第一章

1,using可重定义一个模板,该模板既不是类模板也不是函数模板,是一种新的模板形式:模板别名

templte <typename T>
using func_t=void (*)(T,T);
//使用func_t模板
func_t<int> xxx_2;

2,函数模板的参数在使用上与其他默认函数略不同,它没有必须写在参数表最后的限制。

template <typename R = int , typename U>
R func(U val)
{
val;
}
int main(void)
{
func(123);
return 0;
}

但在调用函数模板的时候,若显示指定了模板的参数,由于参数填充顺序是从左到右的,因此下面这样 调用函数模板返回的是long,不是int
func(123); //func的返回值类型是long

3,当默认模板参数和模板参数自动推导同时使用时,若函数模板无法自动推导出参数类型,则编译器将使用默认模板参数;否则将使用自动推导出的参数类型。
优先级:自动推导出的参数类型 > 默认模板参数

4,POD类型
粗略上来讲,POD是C++为兼容C的内存布局而设计的,主要用于修饰用户自定义类型。
但POD却远比这个要复杂。POD(Plain Old Data),从字面意思上来看,是平凡普通的老旧格式的数据,POD是一个类型属性,既不是关键字也不会像”volatile”用来修饰类型信息。
POD类型,说明该数据是普通的,不会有什么虚函数啊,虚继承啊,或者内嵌的数据类型很复杂的情况。也就是说,POD类型的C++变量,可以直接用C语言中的struct来解释
直观的来说,POD类型中的O代表了与C语言的兼容性,可以直接使用memcpy()直接复制而不会出现任何问题。POD这个想法的由来就是要支持两种最基本的属性:
(1)支持静态初始化
(2)编译C++中的POD类型所得到的内存布局,和C中编译struct的内存布局相同

具体地,C++11将POD类型划分为两个概念:
trivial
standard layout
在C++11中,更多的是用trivial和standard类代替POD类型。

trivial意思是无意义,这个trivial和non-trivial是对类的四种函数来说的:
构造函数(ctor)
复制构造函数(copy)
赋值函数(assignment)
析构函数(dtor)
如果至少满足下面3条里的一条:
显式(explict)定义了这四种函数。
类里有非静态非POD的数据成员。
有基类。
那么上面的四种函数是non-trivial函数

5,在使用初始化列表时,什么样的类型C++会认为它是一个聚合体
(1)类型是一个普通数组
(2)类型是一个类,且

无用户自定义的构造函数
无私有或者保护的非静态数据成员
无基类
无虚函数
不能有{}和=直接初始化的非静态数据成员
聚合类型的定义并非递归的,当一个类的非静态成员是非聚合类型时,这个类也有可能是聚合类型,可以列表初始化。

6,std::initializer_list拥有与一个无参数的构造函数;同时它是非常高效的,它只保存列表中的数据的引用。因此下面的做法是错误的:

std::initializer_list<int> func()
{
int a =1,b=2;
return {a,b};
}

这样虽然可以通过编译,但是无法得到希望的结果,a,b的生命周期在调用后结束,引用的将是不确定的内容。
可以改为:

std::vector<int> func()
{
int a =1,b=2;
return {a,b};
}

7,列表初始化对于类型收窄会报错

8,可调用对象
(1)函数指针
(2)具有operator()成员函数的类对象
(3)一个可被转为函数指针的类对象
(4)一个类成员指针
可调用类型的定义不包括函数类型或者函数引用(只有函数指针),因为函数类型不能直接用来定义对象;而函数引用从某种意义上来说可以看做是一个const的函数指针。

9,std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。

10,std::bind的返回类型是一个stl内部定义的仿函数类型,可以直接赋值给一个std::function

auto newCallable=bind(callable.arg_list)
newCallable本身是一个可调用对象

例子:

#include <iostream>
#include <functional>

void output(int x,int y){
    std::cout<<x<<" "<<y<<std::endl;
}

int main(int argc, char **argv) {
    std::bind(output,1,2)();// 输出1 2
    //等价于
    auto f=std::bind(output,std::placeholders::_1,std::placeholders::_2);
    f(1,2); //输出1 2
    //等价于
    std::bind(output,std::placeholders::_1,std::placeholders::_2)(1,2);// 输出1 2

    std::bind(output,std::placeholders::_1,2)(1); //输出 1 2
    std::bind(output,2,std::placeholders::_1)(1); //输出2 1
    //std::bind(output,2,std::placeholders::_2)(1); //error 调用时没有第二个参数
    std::bind(output,2,std::placeholders::_2)(1,2); //输出 2 2
    std::bind(output,std::placeholders::_2,std::placeholders::_1)(1,2); //输出 2 1
}

结果:

1 2
1 2
1 2
1 2
2 1
2 2
2 1

11,关于std::bind的一些用法总结
最近在看《深入应用c++11》的时候遇到了std::bind的一些新用法,之前没有遇到过,这里记录下。通常时候std::bind是与std::function一起结合使用的,std::bind是一个函数模板,而std::function是一个类模板,这个从其源码就可看出

/**
 *  @brief Function template for std::bind.
 *  @ingroup binders
 */
template<typename _Func, typename... _BoundArgs>
  inline typename
  _Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
  bind(_Func&& __f, _BoundArgs&&... __args)
  {
    typedef _Bind_helper<false, _Func, _BoundArgs...> __helper_type;
    typedef typename __helper_type::__maybe_type __maybe_type;
    typedef typename __helper_type::type __result_type;
    return __result_type(__maybe_type::__do_wrap(std::forward<_Func>(__f)),
             std::forward<_BoundArgs>(__args)...);
  }

template<typename _Signature>
    class function;

std::bind的常见用法
之前的理解仅仅是将bind当做绑定一个全局函数,现在又遇到了一些其他的用法,直接上代码吧

/*
 * main.cpp
 *
 *  Created on: 2017年12月3日
 *      Author: Administrator
 */
#include  <iostream>
#include <functional>

void output(int x, int y)
{
    std::cout << x << " " << y << std::endl;
}
class A
{
public:
    int i_ = 0;

    void output(int x, int y)
    {
        std::cout << x << " " << y << std::endl;
    }

    void operator()() const //无参数 无返回值的仿函数
    {
        std::cout <<"仿函数"<< std::endl;
    }
};

int main(void)
{
    //1,绑定全局函数
    std::bind(output,1,2); //全局函数,仅仅是绑定,没有调用
    std::bind(output,1,2)();//绑定并调用全局函数

    //2,绑定成员函数
    A a;
    std::function<void(int, int)> fr =
        std::bind(&A::output, &a /*调用者*/, std::placeholders::_1, std::placeholders::_2);
    fr(1, 2);  //输出 1 2

    //3,绑定成员变量(包括静态的成员变量) 成员变量这里function中是int&(void)
    std::function<int&(void)> fr_i = std::bind(&A::i_, &a/*调用者*/);  //vs13的bug,绑定成员变量要报错
    fr_i() = 123;

    std::cout << a.i_ << std::endl;  //输出 123
    std::cout << fr_i() << std::endl;  //输出 123

    A a1;
    std::function<int&(void)> fr_i_1 = std::bind(&A::i_, a1/*调用者*/); //调用者没有传指针
    fr_i_1() = 123;

    std::cout << a1.i_ << std::endl;  //输出 0
    std::cout << fr_i_1() << std::endl;  //输出 123

    //4,仿函数
    std::function<void(void)> op = std::bind(&A::operator(),a);
    op();

    return 0;
}

结果如下:

1 2
1 2
123
123
0
123
仿函数

12,lambda表达式通过捕获列表捕获一定范围内的变量

[]不捕获任何变量
[&]捕获外部作用域中所有变量,并作为引用在函数体内引用
[=]捕获外部作用域中所有变量,按值捕获
[=,&foo]按值捕获外部作用域的所有变量,并按引用捕获foo变量
[bar] 仅仅只值捕获bar变量
[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样访问权限。如果已经使用了&或者=,就默认添加此项。
捕获this的目的是可以在lambda中使用当前类的成员函数和成员变量

13,lambda无法修改通过赋值方式捕获的外部变量。
易出错点:lambda的延时调用,注意值捕获与引用捕获的时候,延时调用的区别

14,lambda的类型在c++11中被称为“闭包类型”,可认为其是一个仿函数。

    std::function<int(int)> f1=[](int a){return a;};
    std::function<int(int)> f2=std::bind([](int a){return a;},123);
    std::function<int(void)> f3=std::bind([](int a){return a;},123);

这里函数f2和f3都是绑定的同一个函数,但是f2却是带有int参数,f3无参数

15,没有捕获变量的lambda表达式可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针。

16,按c++的标准,lambda的operator()默认是const,如果是按值捕获的话,const成员函数是无法修改成员变量的值,而mutable的作用就是取消operator()的const属性。

17,tuple简单的创建与取值方式

    //创建方式1
    tuple<const char*,int> tp=make_tuple("123",1);

    //创建方式2
    int x=1;
    int y=2;
    string s="aa";
    auto tp1=std::tie(x,s,y);//tp的类型实际为std::tuple<int&,string&,int&>

    //取值方式1
    const char * data = tp.get<0>(); //获取第一个值
    int len=tp.get<1>(); //获取第二个值

    //取值方式2
    int x,y;
    string a;
    std::tie(x,a,y) = tp1;
    std::tie(std::ignore,std::ignore,y) =tp1; //只解第三个值

其中std::tie创建的是一个元组的左值引用

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值