noexcept异常标识符
在新标准下,函数可以通过提供noexcept
标识符来指定它不会抛出异常。函数参数列表后面的关键字noexcept
表示该函数不会抛出:
Code:
void recoup(int) noexcept; // won't throw
void alloc(int); // might throw
上述代码中recoup
不会抛出任何异常,而alloc
可能会抛出异常。我们说recoup
有一个非nonthrowing specification。
noexcept
说明符必须出现在所有声明和函数的相应定义上,或者不出现在任何声明上。说明符在尾随返回之前。我们还可以在函数指针的声明和定义上指定noexcept
。它可能不会出现在typedef
或类型别名中。在成员函数中,noexcept
说明符跟随在任何const
或引用限定符之后,并且它在虚函数上的final
,override
或= 0
之前。
noexcept运算符
noexcept
说明符的参数通常使用noexcept
运算符构成。noexcept
运算符是一元运算符,它返回一个bool
类型的右值常量表达式,指示给定表达式是否可能抛出。与sizeof
一样,noexcept
不计算其操作数。
例如,下面的表达式将得到true
:
Code:
noexcept(recoup(i)) // true if callingrecoup can't throw, false otherwise
因为我们用noexcept
说明符声明了recoup
。更一般的:
Code:
noexcept(e)
如果e
调用的所有函数都具有非抛出标识符且e
本身不包含throw
,则上式为true
。否则上式返回false
。
我们可以使用noexcept
运算符来形成异常说明符,如下所示:
Code:
void f() noexcept(noexcept(g())); // f has same exception specifier as g
如果函数g
承诺不抛出,则f也是非抛出的。如果g
没有异常说明符,或者有一个允许异常的异常说明符,那么f
也可能抛出。
注:noexcept
有两个含义:当它跟随在函数的参数列表之后时,它是一个异常说明符;当用作noexcept
异常说明符的bool
参数时,它是一个运算符。
内联命名空间
新标准引入了一种新的嵌套命名空间,即内联命名空间。与普通的嵌套命名空间不同,内联命名空间中的名称可以像使用封闭命名空间的直接成员一样使用。也就是说,我们不需要通过命名空间名称限定内联命名空间中的名称。我们只能使用封闭命名空间的名称来访问它们。
内联命名空间是通过在关键字namespace
前面加上关键字inline
来定义的:
Code:
inline namespace FifthEd {
// namespace for the code from the Primer Fifth Edition
}
namespace FifthEd { // implicitly inline
class Query_base { /* ... * /};
// other Query-related declarations
}
关键字inline
必须出现在命名空间的第一个定义中。如果后面重新打开命名空间,则关键字inline
不是必须的,但可以重复使用。
当代码从应用程序的一个版本更改为下一个版本时,通常会使用内联命名空间。例如,我们可以将当前版本的Primer
中的所有代码放入内联命名空间。以前版本的代码将位于非内联命名空间中:
Code:
namespace FourthEd {
class Item_base { /* ... */};
class Query_base { /* ... */};
// other code from the Fourth Edition
}
整个cplusplus_primer
命名空间将包括两个命名空间的定义。例如,假设每个命名空间都在具有相应名称的头文件中定义,我们将cplusplus_primer
定义如下:
Code:
namespace cplusplus_primer {
#include "FifthEd.h"
#include "FourthEd.h"
}
因为FifthEd
是内联的,所以引用cplusplus_primer::
的代码将从该命名空间获取版本。如果我们想要早期版本的代码,我们可以像使用任何其他嵌套命名空间一样访问它,方法是使用所有封闭命名空间的名称:例如:
Code:
cplusplus_primer::FourthEd::Query_base
继承的构造函数和多重继承
在新标准下,派生类可以从一个或多个基类继承其构造函数。从多个基类继承相同的构造函数(即具有相同参数列表的构造函数)是错误的:
Code:
struct Base1 {
Base1() = default;
Base1(const std::string&);
Base1(std::shared_ptr<int>);
};
struct Base2 {
Base2() = default;
Base2(const std::string&);
Base2(int);
};
// error: D1 attempts to inherit D1::D1 (const string&) from both base classes
struct D1: public Base1, public Base2 {
using Base1::Base1; // inherit constructors from Base1
using Base2::Base2; // inherit constructors from Base2
};
从多个基类继承相同构造函数的类必须定义其自己的构造函数版本:
Code:
struct D2: public Base1, public Base2 {
using Base1::Base1; // inherit constructors from Base1
using Base2::Base2; // inherit constructors from Base2
// D2 must define its own constructor that takes a string
D2(const string &s): Base1(s), Base2(s) { }
D2() = default; // needed once D2 defines its own constructor
};
参考文献
[1] Lippman S B , Josée Lajoie, Moo B E . C++ Primer (5th Edition)[J]. 2013.
网友评论