C++11部分特性

预定义宏

1. func预定义标识符

功能:返回所在函数的名字
C++11中甚至允许在类或结构体中使用:

#include
using namespace std;

class TestStruct {
public:
  TestStruct () : name(__func__) {}
  const char *name;
}; 

int main() {
  TestStruct ts;
  cout << ts.name <

原理:编译器隐式地在函数定义后定义func表示符
所以需要注意的是func不能作为函数参数的默认值,因为在参数声明的时候,func还没有被定义

void testFun(string func_name = __func__) {};  //compile error

2.宏__cplusplus

C++11的__cplusplus被预定义为201103L,可以用

#ifdef __cplusplus < 201103L
    #error "please use C++11 implementation"
#endif

进行检测

静态断言

assert函数是在运行时进行断言,而当需要在编译时断言则需要使用静态断言,在C++11中,引入了static_assert,接受两个参数,static_assert ( bool_constexpr , message )一个是断言表达式(通常返回bool值),一个是警告信息

当然,利用“不能除以0”的性质也可以实现静态断言,但效果明显没有C++11标准中的好(毕竟标准直接报错警告信息,而这样实现只会报不能/0,这样还会增加调试难度)

#include
#include
using namespace std;

#define assert_static(e) \
  do{ \
     enum{ assert_static__ = 1/ (e) }; \
  }while (0)
  
template  int bit_copy(T&a, U& b){
  assert_static(sizeof(b) == sizeof(a));
}
  
int main(){
  int a = 1;
  double b = 3;
  bit_copy(a,b);
}

noexcept修饰符与noexcept操作符

noexcept比throw()在效率上会高一些,在 C++11中,noexcept替代了throw()

noexcept修饰符

noexcept修饰符有两种形式,一种是直接加上关键字noexcept,而另外一种则可以接受一个常量表达式作为参数
void excpt_func() noexcept (常量表达式);
量表达式的结果会被转换成一个bool类型的值。该值为true,表示函数不会抛出异常,反之,则有可能抛出异常。这里,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。
在通常情况下,在C++11中使用noexcept可以有效地阻止异常的传播与扩散。

noexcept操作符

noexcept作为一个操作符时,通常可以用于模板。
我的测试代码:

#include
#include
using namespace std;

class Test{
public:
  Test() {
    throw 1;
    cout<<"constructor"<
  void fun() noexcept(noexcept(T())) {
    throw 1;
  }
  
int main(){
  try{
    fun(); 
  }
  catch(...){
    cout<<"caught"<(); 
  }
  catch(...){
    cout<<"caught"<

noexcept(noexcept(T()))中,第二个noexcept就是一个noexcept操作符。当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true(实际noexcept参数返回false还包括一些情况,这里就不展开讲了)。
对于测试代码中的例子,当模板实参为Test时,Test()可能抛出异常,所以这时候此时签名修饰符为noexcept(false),所以可以抛出异常
而当模板实参为int的时候,noexcept(noexcept(T()))为noexcept(true),所以这时候试图抛出异常的话,会直接调用std::terminate终端程序的执行

另外需要注意的是,析构函数默认为noexcept,delete函数默认为noexcept

快速初始化成员变量

C++11增加允许了使用=或者花括号{}的方式来初始化:
struct init{ int a = 1; double b {1.2}; };
这样的方式也叫就地初始化,然而有一个问题,这样的初始化方式与初始化列表是否冲突?
当然不会冲突:

class Test{
public:
  Test(string ss = "234"):s(ss){}
  
  string s {"123"};
};

你可能感兴趣的:(C++11部分特性)