C++11第一篇
C++11是C++编程语言的一个版本,于2011年发布。C++11引入了许多新特性,为C++语言提供了更强大和更现代化的编程能力。
可变参数模板
在C++11中,可变参数模板可以定义接受任意数量和类型参数的函数模板或类模板。它可以表示0到任意个数,任意类型的参数。通过使用(…)来声明可变参数,省略号后面的参数被称为参数包。
下面是可变参数的函数模板:
// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}
//展开函数的终止
template<class T>
void Showlist(const T& t)
{
cout << t << endl;
}
//可变模板参数
template<class T,class ...Args>
void Showlist(T value, Args... args)
{
cout << value << " ";
Showlist(args...);
}
int main()
{
Showlist(1);
Showlist(1, 'A');
Showlist(1, 'A', std::string("sort"));
return 0;
}
emplace_back()
测试与push_back()的区别:
int main()
{
std::list<fnc::string> lt1;
fnc::string s1("xxxx");
lt1.push_back(s1);
lt1.push_back(move(s1));
cout << "=============================================" << endl;
fnc::string s2("xxxx");
lt1.emplace_back(s2);
lt1.emplace_back(move(s2));
cout << "=============================================" << endl;
lt1.push_back("xxxx");
lt1.emplace_back("xxxx");
cout << "=============================================" << endl;
std::list<pair<fnc::string, fnc::string>> lt2;
pair<fnc::string, fnc::string> kv1("xxxx", "yyyy");
lt2.push_back(kv1);
lt2.push_back(move(kv1));
cout << "=============================================" << endl;
pair<fnc::string, fnc::string> kv2("xxxx", "yyyy");
lt2.emplace_back(kv2);
lt2.emplace_back(move(kv2));
cout << "=============================================" << endl;
lt2.emplace_back("xxxx", "yyyy");
cout << "=============================================" << endl;
return 0;
}
再测试:
class Date
{
public:
Date(int year=1900, int month=1, int day=1)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._day)
{
cout << "Date(const Date& d)" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
//直接在参数中插入
std::list<Date> lt1;
lt1.push_back({ 2024,3,30 });
lt1.emplace_back(2024, 3, 30);
//直接插入已有的对象
cout << endl;
Date d1(2023, 1, 1);
lt1.push_back(d1);
lt1.emplace_back(d1);
//插入匿名对象
cout << endl;
lt1.push_back(Date(2023, 1, 1));
lt1.emplace_back(Date(2023, 1, 1));
return 0;
}
lambda
lambda语法表达式
[capture-list] (parameters) mutable -> return-type { statement}
- [capture-list]:捕捉列表:位于lambda表达式最前位置,编译器通过[]来进行判断,能捕捉上下文中的变量给lambda表达式使用;
- (parameters):参数列表,与函数的参数列表使用一致,如果没有参数的话,可省略使用;
- mutable:默认情况下,lambda函数是一个const函数,使用mutable可以取消const性。使用该单词,不可省略参数列表。
- -> return-type :返回值类型,用于声明函数的返回值类型,没有返回值进行省略;一般有返回值也可以省略,通过编译器进行推导。
- {statement}:函数主体,除了使用参数列表的参数,也可使用捕捉列表的参数。
接下来看lambda的简单使用:
int main()
{
//auto add = [](int a, int b)->int{return a + b; };
auto add = [](int a, int b) {return a + b; };
cout << add(1, 21) << endl;
auto swap = [](int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
};
int x = 2, y = 22;
swap(x, y);
cout << x << " " << y << endl;
auto func = []() {cout << "lambda" << endl; };
func();
return 0;
}
对上面sort的改装:
捕捉列表
#include<algorithm>
int main()
{
int x = 1, y = 2;
auto swap = [&x, &y]()mutable
{
int tmp = x;
x = y;
y = tmp;
};
swap();
cout << x << " " << y << endl;
int m = 3, n = 4;
//传值捕捉'=':捕捉当前域的所有对象
auto func1 = [=]()
{
return m * n - x - y;
};
cout << func1() << endl;
//传引用捕捉:捕捉当前域所有对象
auto func2 = [&]()
{
x++;
y++;
return m * n - x - y;
};
cout << func2() << endl;
//x:2,y:3,m:3,n:4
//对n传值捕捉,其他的传引用捕捉
auto func3 = [&, n]()
{
x++;
y++;
m++;
//n++;错误
return m * n - x - y;
};
cout << func3() << endl;
}
lambda底层
class Rate
{
public:
Rate(double rate) : _rate(rate)
{}
double operator()(double money, int year)
{
return money * _rate * year;
}
private:
double _rate;
};
int main()
{
//函数对象/仿函数
double rate = 0.49;
Rate r1(rate);
r1(10000, 2);
// lambda
auto r2 = [=](double monty, int year)->double {return monty * rate * year;};
r2(10000, 2);
auto f1 = [] {cout << "hello world" << endl; };
auto f2 = [] {cout << "hello world" << endl; };
f1();
f2();
return 0;
}
包装器
为什么要有包装器?
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
cout << useF(f, 11.11) << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
// lamber表达式
cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
return 0;
}
类模板:
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
- Ret:表示调用函数的返回类型;
- Args:表示函数的参数列表的参数;
简单对上面例题使用
#include<functional>
int main()
{
// 函数指针
function<double(double)> fc1 = f;
fc1(11.11);
cout << useF(fc1, 11.11) << endl;
// 函数对象
function<double(double)> fc2 = Functor();
fc2(11.11);
cout << useF(fc2, 11.11) << endl;
// lambda表达式
function<double(double)> fc3 = [](double d)->double { return d / 4; };
fc3(11.11);
cout << useF(fc3, 11.11) << endl;
return 0;
}
类成员函数
int f(int a, int b)
{
return a + b;
}
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
// 普通函数
function<int(int, int)> fc1 = f;
cout << fc1(1, 1) << endl;
// 静态成员函数
function<int(int, int)> fc2 = &Plus::plusi;
cout << fc2(1, 1) << endl;
// 非静态成员函数
// 非静态成员函数需要对象的指针或者对象去进行调用
function<double(Plus, double, double)> fc3 = &Plus::plusd;
cout << fc3(Plus(), 1, 1) << endl;
return 0;
}
bind
在C++中,bind
是一个函数模板,位于<functional>
头文件中,用于创建函数对象(也称为函数绑定器),可以将参数绑定到函数调用中。
bind
函数的语法如下:
template< class Fn, class... Args >
bind( Fn&& fn, Args&&... args );
其中,Fn
表示要绑定的函数或可调用对象,Args
表示要绑定的参数。
使用bind
函数可以实现函数的延迟调用、固定部分参数等功能。
简单使用
int Sub(int a, int b)
{
return a - b;
}
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a - b;
}
};
int main()
{
// 调整参数顺序
int x = 10, y = 20;
cout << Sub(x, y) << endl;
auto f1 = bind(Sub, placeholders::_2, placeholders::_1);
cout << f1(x, y) << endl;
function<double(Plus, double, double)> fc3 = &Plus::plusd;
cout << fc3(Plus(), 1, 1) << endl;
// 调整参数的个数
// 某些参数绑死
function<double(double, double)> fc4 = bind(&Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
cout << fc4(2, 3) << endl;
function<double(double)> fc5 = bind(&Plus::plusd, Plus(), placeholders::_1, 20);
cout << fc5(2) << endl;
return 0;
}