一、template template parameter(模板的模板参数)
template<typename T>
using vec = vector<T, allocator<T>>; //不得在function body内声明
using lst = list<T, allocator<T>>;
template<typename T, template<class> class Container>
class XCLs{
private:
Container<T> c;
public:
XCLs(){
for(long i = 0; i < SIZE; ++i){
c.insert(c.end(), T());
}
output_static_data(T());
Container<T> c1(c);
Container<T> c2(std::move(c));
c1.swap(c2);
}
};
//use case
XCLs<MyString, vec> c1;
二、noexcept
void foo() noexcept; //加上noexcept表明,这个函数不会抛出异常
void foo() noexcept(true);//在条件为true时, 表明不会抛出异常
异常是一定要被处理的。
A调用B,若B抛出异常,且若B不处理,则继续往上面走,到A。(也就是说往源头走直到被处
理)
若一直未被处理,则会调用默认的异常处理函数 std::terminate(); 而这个函数又会调用
std::abort()使得程序中断。
void swap(Type &x, Type &y) noexcept(noexcept(x.swap(y))){
x.swap(y);
}
2、noexcept的作用是在某种条件下函数不会抛出异常。
class MyString{
private:
char* _data;
size_t _len;
public:
//move constructor
MyString(MyString&& str) noexcept:_data(str._data), _len(str._len){
...
}
//move assignment
MyString& operator=(MyString &&str) noexcept{
...
return *this;
}
};
三、override(复写、改写)应用于虚函数
1、override的字面意思是复写,改写,应用在虚函数上。
struct Base{
virtual void cFunc(float){}
};
struct Derived1:public Base{
virtual void vFunc(int){} //出错,虚函数的参数类型不对
};
struct Derived2:public Base{
//出错,虚函数的参数类型不对,但是加入override关键字后,出错会报错
virtual void vFunc(int) override {}
};
四、final
1、final的作用:
对类修饰:表示此类是最后一个,不会再有下一个类继承此类。
对 虚函数修饰:表示不能再子类中对其重写。
应用场景1:
struct Base1 final{}; //加入final关键字后不可被复写
struct Derived : public Base1{};
应用场景2:
struct Base2{
virtual void f() final;
};
struct Derived2 : public Base2{
virtual void f(); //报错,父类的虚函数加了final关键字
};
五、decltype(defines a type equivalent to the type of an expression)
1、C++11引入decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中分析表达式并得到它的类型,却不实际计算表达式的值。
map<string, float> coll;
...
decltype(coll)::value_type elem;
decltype三种应用:
应用1:decltype, used to declare return types(用来声明一个返回类型)
//case 1
template<typename T1, typename T2>
decltype(x+y) add(T1 x, T2 y);
//case 2
template<typename T1, typename T2>
auto add(T1 x, T2 y)->decltype(x+y);
应用2:use it in metaprogramming(元编程)
//按下方使用来看,只可以传入容器类型数据
template<typename T>
void test_decltype(T obj){
typedef typename decltype(obj)::iterator iType;
}
应用3:used ro pass the type of a lambda
auto cmp = [](const Person& p1, const Person& p2){
return p1.lastName() < p2.lastName()
}
std::set<Person, decltype(cmp)> coll(cmp);
注意:面对lambde,我们手上往往只有object,没有type。要获得其type就得借助于decltype。
六、Lambdas表达式
C++11 introduced lambdas, allowing the definition of inline functionality, which can be used as a parameter or a local object. Lambdas change the way the C++ standard library is used.
[](){
std::cout << "hello lambda" << std::endl;
}
//you can call it directly
[](){
std::cout << "hello lambda" << std::endl;
}();
//or pass it to objects to get called
auto I = [](){
std::cout << "hello lambda" << std::endl;
}
I(); //print "Hello lambda"
详细环节介绍:
[...](...) mutable throwSpec -> retType{
...
}
1、[]叫做捕获说明符,里面放的是截取外部变量的方式,表示一个lambda表达式的开始。 2、()普通参数列表,是函数传入的参数
3、mutable表示捕获的变量在函数体内部可否修改。
4、throwSpec表示抛出异常
5、->type表示返回类型,如果没有返回类型,则可以省略这部分。这涉及到c++11的另一特性,参见自动类型推导,最后就是函数体部分。
注意:
mutable throwSpec -> type这三个都是可写可不写,但三个有一个存在,则()必须写,若是三个 一个 都没有,则()可写可不写。
[]外部变量的捕获规则:
int id = 0;
auto i = [id]() mutable {
...
}
//注:id在lambda表达式中是以值的形式传进去的,不可修改,为了可以在lambda表达式中修改id的值,需要添加mutable关键字