1、{}的用法:
2、for的新用法、auto类型的用法:
3、返回类型后置:
4、使用auto明确模板函数的输出类型:
5、类的构造函数可以被其他类调用初始化:
6、nullptr与NULL:
7、更安全的枚举类型,可以见枚举值隐藏:
关键词:
1、inline关键词:
2、static关键词:
全局static
局部static
static函数
static成员变量
static成员函数
3、assert:
4、decltype
推导规则decltype(exp)
与using/typedef结合,用于类型定义
重用匿名类型
结合auto用于类型推导
一些用法:
1、{}的用法:
struct IdString
{
std::string name;
int identifier;
};
IdString var3{"SomeName", 4};
IdString GetString()
{
return {"SomeName", 4}; //可以直接返回结构体
}
2、for的新用法、auto类型的用法:
for (vector ::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
for (auto &x : myvec.cbegin()) //用auto替换
int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array)
{x *= 2;}
for (auto &x : my_array)
{x *= 2;}
这种for语句还可以用于C型数组,初始化列表,和任何定义了begin()和end()来回返首尾迭代器的类型。
3、返回类型后置:
template <typename U, typename V>
auto foo(U u, V v) -> decltype(u*v){
return u*v;
}
//decltype并不会计算值,只会计算类型
这样就能明确u*v的类型了
4、使用auto明确模板函数的输出类型:
template <typename LHS, typename RHS>
//以下要注意-> decltype(lhs+rhs)这个用法
auto AddingFunc(const LHS &lhs, const RHS &rhs) -> decltype(lhs+rhs)
{
return lhs + rhs;
}
5、类的构造函数可以被其他类调用初始化:
class SomeType {
int number;
string name;
SomeType( int i, string& s ) : number(i), name(s){}
public:
SomeType( ) : SomeType( 0, "invalid" ){}
SomeType( int i ) : SomeType( i, "guest" ){}
SomeType( string& s ) : SomeType( 1, s ){ PostInit(); }
};
class BaseClass{
public:
BaseClass(int iValue);
};
class DerivedClass : public BaseClass{
public:
using BaseClass::BaseClass; //可以继承基类的构造函数,但是要不就全部继承,要不就一个都不要继承
};
6、nullptr与NULL:
void foo(char *);
void foo(int);
void foo(nullptr_t);
char* pc = nullptr; // OK
int * pi = nullptr; // OK
int i = nullptr; // error nullptr不能隐式转换为整数,也不能和整数做比较。
bool b = nullptr; // OK
foo(pc); // 调用foo(char *), 而不是 foo(int), 也不是void foo(nullptr_t);
foo(nullptr); // 调用foo(nullptr_t);
7、更安全的枚举类型,可以见枚举值隐藏:
enum class myEnumeration : unsigned int
{
Val1,
Val2,
Val3 = 100,
Val4 /* = 101 */,
};
Enum1::Val1是有意义的表示法,而单独的Val1则否
此种枚举为类型安全的。枚举类别不能隐式地转换为整数;也无法与整数数值做比较。(表示式Enumeration::Val4 == 101会触发编译期错误)。这时候需要执行强制转换才能比较。
关键词:
1、inline关键词:
inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。
如下不构成内联函数:
inline void Foo(int x, int y); // inline 仅与函数声明放在一起
void Foo(int x, int y){}
而如下构成内联函数:
void Foo(int x, int y);
inline void Foo(int x, int y) // inline 与函数定义体放在一起{}
2、static关键词:
有的公司编码规范明确规定只用于本文件的函数要全部使用static关键字声明,这是一个良好的编码风格。
全局static
如果想多个文件共享变量,但是在头文件中声明了static变量,则头文件被包含了多少次,这个static变量就被创建了多少次,它们之间互不关联。
一个进程在内存中的分布如下图:
- .text段保存进程所执行的程序二进制文件
- .data段保存进程所有的已初始化的全局变量
- .bss段保存进程未初始化的全局变量(其他段中还有很多乱七八糟的段,暂且不表)。
在进程的整个生命周期中,.data段和.bss段内的数据在进程结束之后才会被释放。
当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以:如果想在其他文件中也访问,就不要在头文件中声明static变量!!!
局部static
- 位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。
- 访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。
- 值:静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,只有一份,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。(多线程注意!!!)
static函数
当你的程序中有很多个源文件的时候,你肯定会让某个源文件只提供一些外界需要的接口,其他的函数可能是为了实现这些接口而编写,这些其他的函数你可能并不希望被外界(非本源文件)所看到,这时候就可以用static修饰这些“其他的函数”。
static函数的作用域是本源文件,把它想象为面向对象中的private函数就可以了。
static成员变量
- 静态数据成员是类的成员,无论定义了多少个类的对象,静态数据成员的拷贝只有一个,且对该类的所有对象可见。也就是说任一对象都可以对静态数据成员进行操作。而对于非静态数据成员,每个对象都有自己的一份拷贝。
- 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性。
static成员函数
- 没有this指针,因此只能调用其他static成员函数。
- 非静态成员函数可以任意地访问静态成员函数和静态数据成员。(因为static在程序载入时就被初始化?)
3、assert:
debug阶段要使用assert?assert中文解释是 断言 ,比如说,“我断言x一定大于0”。是用于排除错误的,而非异常。
assert可能默认是关闭的,此时需要在include前用宏打开:
#undef NDEBUG
#include <assert.h>
//...
aseert(exp); //exp为0时断言失败,不为0时断言成功,表示正确。
//...
assert()应该遵循使用原则,每次断言只能检验一个判断式。
assert(exp1 && exp2 && exp3);
//应该修改为
assert(exp1);
assert(exp2);
assert(exp3);
但是在 release版本应该关闭assert ,因其会造成较大的性能损耗,可以在代码测试或者merge之前,关闭assert
4、decltype
decltype与auto关键字一样,用于进行编译时类型推导
推导规则decltype(exp)
- exp是一个不被()包括的表达式、变量,则decltype(exp)的类型和exp一致。
- exp是函数的调用,则和函数返回值类型一致。
- exp是一个左值,或者被()包括,则是exp的引用。假设类型T,则decltype((T))类型为&T。
左值、右值
int n = 0, m = 0;
decltype(n + m) c = 0; //n+m 得到一个右值,符合推导规则一,所以推导结果为 int
decltype(n = n + m) d = c; //n=n+m 得到一个左值,符号推导规则三,所以推导结果为 int&
与using/typedef结合,用于类型定义
与auto效果相同,但是auto 只能用于类的静态成员,不能用于类的非静态成员(普通成员),如果我们想推导非静态成员的类型,这个时候就必须使用 decltype 了
using size_t = decltype(sizeof(0));//sizeof(a)的返回值为size_t类型
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
vector<int >vec; typedef decltype(vec.begin()) vectype;
for (vectype i = vec.begin; i != vec.end(); i++) { //... }
重用匿名类型
//匿名struct
struct
{
int a;
int b;
}S;
decltype(S) s;
结合auto用于类型推导
template <typename U, typename V>
auto foo(U u, V v) -> decltype(u*v){
return u*v;
}