cpp11特性(一)
1.查验机器环境
#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
*/
2.返回函数的名字
// 返回函数的名字,预定义标识符 __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
*/
3.变长参数宏定义
// 变长参数宏定义 __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
*/
4.静态断言与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;
}
5.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()用于模板
6.快速初始化成员变量
#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;
}
7.override和final
- override:保证在派生类中声明的重载函数,与基类的虚函数有相同的签名(函数名,参数,const属性);
- final:阻止类的进一步派生 和 虚函数的进一步重写。
加了override,明确表示派生类的这个虚函数是要重写基类的,如果派生类与基类虚函数的签名不一致,编译器就会报错。一个虚函数被声明为final,则派生类不能再重写它。
8.模板函数的默认模板参数
c++98不支持函数模板的默认模板参数,c++11支持。
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可以通过编译

浙公网安备 33010602011771号