学习《深入应用c++11》1

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 代码优化与工程级应用

posted @ 2019-12-30 16:43  sfdevs  阅读(333)  评论(0)    收藏  举报