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可以通过编译
posted @ 2022-12-19 15:37  无知亦乐  阅读(92)  评论(0)    收藏  举报