# 查验机器环境

#include <iostream>
using namespace std;
int main() {
    cout << "Standard Clib: " << __STDC_HOSTED__ << endl;
    cout << "Standard C: " << __STDC__ << endl;
    // cout << "C Standard version: " << __STDC_VERSION__ << endl;
    cout << "ISO/IEC " << __STDC_ISO_10646__ << endl;
    return 0;
}
Standard Clib: 1
Standard C: 1
ISO/IEC 201706

# 返回函数的名字

// 返回函数的名字,预定义标识符 __func__
#include <iostream>
#include <string>
using namespace std;
const char *hello() { return __func__; }
const char *world() { return __func__; }
struct TestStruct {
    TestStruct() : name(__func__) {}
   const char *name;
};
int main() {
    cout << hello() << ", " << world() << endl;
    TestStruct ts;
    cout << ts.name << endl; 
   return 0;
}
hello, world
TestStruct

# 变长参数宏定义

// 变长参数宏定义 __VA_ARGS__
#include <stdio.h>
#define LOG(...) {  \
    fprintf(stderr, "%s: Line %d:\t", __FILE__, __LINE__); \
    fprintf(stderr, __VA_ARGS__); \
    fprintf(stderr, "\n"); \
}
int main() {
    int x = 3;
    LOG("x = %d", x);
    return 0;
}
va_args.cpp: Line 13:   x = 3

# 静态断言与 static_assert

  • 断言宏 assert 只用于程序运行时
  • #error 只在编译器预处理时有效
  • static_assert 用于程序编译时进行断言

static_assert 接收两个参数,一个 bool 值,一个字符串警告信息。

static_assert 的断言表达式的结果必须时在编译时期就可以计算的表达式,及必须是常量表达式。

#include <cstring>
using namespace std;
template <typename T, typename U> int bit_copy(T &a, U &b) {
    static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have same width.");
    memcpy(&a, &b, sizeof(b));
}
int main() {
    int a = 0x2468;
    double b;
    bit_copy(a, b);
    return 0;
}

# noexcept 修饰符与 noexcept 操作符

  • noexcept 不会抛出异常,通过调用 std::terminate () 来终止程序的运行,则这样可以减少异常机制带来的开销(比如,不用进行栈帧的一级一级的展开),有效的阻止了异常的传播与扩散。
  • 但也可能存在一些问题,比如 noexcepet 后无法保证对象的析构函数的正常调用,无法保证栈的自动释放等等。
  • C++11 默认将 delete 函数设置为 noexcept,即 nocept (true),可以提高程序的安全性。
`void operator delete(void *) noexcept;
void operator delete[](void *) noexcept;
void *operator new(std::size_t) noexcept(false);  // 可以抛出异常
void *operator new[](std::size_t) noexcept(false); // 可以抛出异常
void except_func() noexcept;   // 用于函数,默认 noexcept (true)
void except_func() noexcept(常量表达式)  // 用于函数
template <class T>
void fun() noexcept(noexcept(T(()))) {} //noexcept () 用于模板 `

# 快速初始化成员变量

#include <string>
using namespace std;
struct C {
    C(int i) : c(i) {};
    int c;
};
struct Init {
    int a = 1;				// 可以通过编译,以前的 C++98 不能通过编译
    string b("hello");		// 无法通过编译
    C c(1);					// 无法通过编译
};
int main() {
    Init temp;
    return 0;
}`

# override 和 final

  • override:保证在派生类中声明的重载函数,与基类的虚函数有相同的签名(函数名,参数,const 属性);
  • final:阻止类的进一步派生 和 虚函数的进一步重写。

加了 override,明确表示派生类的这个虚函数是要重写基类的,如果派生类与基类虚函数的签名不一致,编译器就会报错。一个虚函数被声明为 final,则派生类不能再重写它。

# 模板函数的默认模板参数

c98 不支持函数模板的默认模板参数,c11 支持。

void Deparm(int m = 3) {}   //c++98 编译通过, c++11 编译通过
template <typename T = int >
	class DefClass {};		//c++98 编译通过, c++11 编译通过
template <typename T = int >
	void DefTempParm() {}   //c++98 编译不通过, c++11 编译通过 `

对于类模板,如果定义模板类的默认模板参数,必须按照从左到右定义。而对于函数模板没有此要求。

template<typename T1, typename T2 = int> class DefClass1;	//c++11 可以通过编译
template<typename T1 = int, typename T2> class DefClass2;	//c++11 不能通过编译
template<typename T, int i = 0> class DefClass1;  //c++11 可以通过编译
template<int i= 0, typename T> class DefClass1;	  //c++11 不能通过编译
template<typename T1 = int, typename T2> void DefFunc1(T1 a, T2 b);	//c++11 可以通过编译
template<int i= 0, typename T> void DefFunc2(T a);					//c++11 可以通过编译 `