这是C++11新特性介绍的第十一部分,涉及到一些不好归类的新特性。
不想看toy code的读者可以直接拉到文章最后看这部分的总结。
类型别名声明
类似typedef,新标准中可以使用using为类型声明一个别名(alias)。
range for
range for语句在之前的章节中已经见识过了:
这里需要注意的是,在第二个例子中,range for语句中可以直接使用引用,从而修改被迭代遍历的对象本身。
另外,range for不能用于动态分配内存的数组,因为动态分配的内存中没有begin、end方法可供调用。
新的除法舍入规则
新标准中,重新统一了除法的舍入规则。主要需要留意两数符号不同时的规则:
(-x) / y = x / (-y) = – (x / y)
x % (-y) = x % y
(-x) % y = – (x % y)
尾置返回类型
之前,我们也见识过尾置返回类型和decltype的配合使用。有时,采用尾置返回类型,代码的可读性更高。
使用字符串作为文件名
在新标准中,可以直接使用string作为文件名进行文件流处理,而不必要求C风格字符数组。
字符串和数值的转换
新标准中,添加了多个函数用于string和数值之间的转换。
bind 函数
新标准中,提供了功能更强大的参数绑定函数bind,用于替换原有的bind1st和bind2nd。
std::placeholders::_1表示占位符,指代第1个参数,等待后续真正调用时由用户传入。
显式类型转换
新标准中,可以指定一个类型转换为显式(explicit)的。指定为显式的类型转换,不能再进行隐式转换。
这其中有一个例外,即,即使指定一个类型和bool类型之间的转换是显式的,在if语句中,也仍然可以执行隐式类型转换。
内联命名空间
新标准中引入了内联命名空间。内联命名空间内的名字可以不加命名空间名字前缀,直接在外层命名空间中使用。这为我们设置一个默认的命名空间提供了方便。
只需在第一次声明内联命名空间时加上inline关键字,之后就可以省略了。
限定作用域的 enum
新标准中,可以通过enum class foo这样的形式定义一个限定作用域的枚举,其中的枚举变量在作用域之外不可见。
其中,one、two、three就只能在number限定的作用域中可见,而CHN、USA、FRA就没有这个限制。
指定枚举的数据类型
新标准中,可以指定枚举的数据类型为除了int之外的其他整数类型。
输出
整个测试程序的输出结果如下:
总结
类似typedef,新标准中可以使用using为类型声明一个别名(alias)。
range for语句可以方便的迭代对象,并且支持引用迭代。
range for不能用于动态分配内存的数组。
新标准中,重新统一了除法的舍入规则。主要需要留意两数符号不同时的规则:
(-x) / y = x / (-y) = – (x / y)
x % (-y) = x % y
(-x) % y = – (x % y)
可以采用尾置返回类型,提高代码的可读性。
可以直接使用string作为文件名进行文件流处理,而不必要求C风格字符数组。
添加了多个函数用于string和数值之间的转换。
提供了功能更强大的参数绑定函数bind,用于替换原有的bind1st和bind2nd。
可以指定一个类型转换为显式(explicit)的。指定为显式的类型转换,不能再进行隐式转换。有一个例外,即,即使指定一个类型和bool类型之间的转换是显式的,在if语句中,也仍然可以执行隐式类型转换。
引入了内联命名空间。内联命名空间内的名字可以不加命名空间名字前缀,直接在外层命名空间中使用。
可以通过enum class foo这样的形式定义一个限定作用域的枚举,其中的枚举变量在作用域之外不可见。
不想看toy code的读者可以直接拉到文章最后看这部分的总结。
类型别名声明
类似typedef,新标准中可以使用using为类型声明一个别名(alias)。
range for
range for语句在之前的章节中已经见识过了:
这里需要注意的是,在第二个例子中,range for语句中可以直接使用引用,从而修改被迭代遍历的对象本身。
另外,range for不能用于动态分配内存的数组,因为动态分配的内存中没有begin、end方法可供调用。
新的除法舍入规则
新标准中,重新统一了除法的舍入规则。主要需要留意两数符号不同时的规则:
(-x) / y = x / (-y) = – (x / y)
x % (-y) = x % y
(-x) % y = – (x % y)
尾置返回类型
之前,我们也见识过尾置返回类型和decltype的配合使用。有时,采用尾置返回类型,代码的可读性更高。
使用字符串作为文件名
在新标准中,可以直接使用string作为文件名进行文件流处理,而不必要求C风格字符数组。
字符串和数值的转换
新标准中,添加了多个函数用于string和数值之间的转换。
bind 函数
新标准中,提供了功能更强大的参数绑定函数bind,用于替换原有的bind1st和bind2nd。
std::placeholders::_1表示占位符,指代第1个参数,等待后续真正调用时由用户传入。
显式类型转换
新标准中,可以指定一个类型转换为显式(explicit)的。指定为显式的类型转换,不能再进行隐式转换。
这其中有一个例外,即,即使指定一个类型和bool类型之间的转换是显式的,在if语句中,也仍然可以执行隐式类型转换。
内联命名空间
新标准中引入了内联命名空间。内联命名空间内的名字可以不加命名空间名字前缀,直接在外层命名空间中使用。这为我们设置一个默认的命名空间提供了方便。
只需在第一次声明内联命名空间时加上inline关键字,之后就可以省略了。
限定作用域的 enum
新标准中,可以通过enum class foo这样的形式定义一个限定作用域的枚举,其中的枚举变量在作用域之外不可见。
其中,one、two、three就只能在number限定的作用域中可见,而CHN、USA、FRA就没有这个限制。
指定枚举的数据类型
新标准中,可以指定枚举的数据类型为除了int之外的其他整数类型。
输出
整个测试程序的输出结果如下:
总结
类似typedef,新标准中可以使用using为类型声明一个别名(alias)。
range for语句可以方便的迭代对象,并且支持引用迭代。
range for不能用于动态分配内存的数组。
新标准中,重新统一了除法的舍入规则。主要需要留意两数符号不同时的规则:
(-x) / y = x / (-y) = – (x / y)
x % (-y) = x % y
(-x) % y = – (x % y)
可以采用尾置返回类型,提高代码的可读性。
可以直接使用string作为文件名进行文件流处理,而不必要求C风格字符数组。
添加了多个函数用于string和数值之间的转换。
提供了功能更强大的参数绑定函数bind,用于替换原有的bind1st和bind2nd。
可以指定一个类型转换为显式(explicit)的。指定为显式的类型转换,不能再进行隐式转换。有一个例外,即,即使指定一个类型和bool类型之间的转换是显式的,在if语句中,也仍然可以执行隐式类型转换。
引入了内联命名空间。内联命名空间内的名字可以不加命名空间名字前缀,直接在外层命名空间中使用。
可以通过enum class foo这样的形式定义一个限定作用域的枚举,其中的枚举变量在作用域之外不可见。
可以指定枚举的数据类型为除了int之外的其他整数类型。
#include <iostream> | |
#include <fstream> | |
#include <functional> | |
#include <limits.h> | |
int (*dummy_ret1(int i))[5] | |
{ | |
static int ret1[5] = {i, i*2, i*3, i*4, i*5}; | |
int(*pret)[5] = &ret1; | |
return pret; | |
} | |
auto dummy_ret2(int i) -> int (*)[5] | |
{ | |
static int ret2[5] = {i+1, i+2, i+3, i+4, i+5}; | |
int(*pret)[5] = &ret2; | |
return pret; | |
} | |
int add_int(int a, int b) | |
{ | |
return a + b; | |
} | |
class OtherType | |
{ | |
public: | |
OtherType(int i) : val(i){} | |
explicit operator int() {return val;} | |
explicit operator bool() {return val != 0;} | |
private: | |
int val; | |
}; | |
inline namespace InlineSpace | |
{ | |
int inline_val1 = 1; | |
} | |
namespace InlineSpace | |
{ | |
int inline_val2 = 2; | |
} | |
namespace NormalSpace | |
{ | |
int normal_val3 = 3; | |
} | |
int main() | |
{ | |
std::cout<<"test using alias:\n"; | |
using HT = double; | |
using NAME = std::string; | |
HT h = 1.78; | |
NAME name = "Robert"; | |
std::cout<<name<<"'s height is "<<h<<std::endl; | |
std::cout<<"test using alias done.\n"<<std::endl; | |
std::cout<<"test range for:\n"; | |
std::string nation = "CHINA"; | |
for(auto c : nation) | |
std::cout<<c<<" "; | |
std::cout<<"\n"; | |
for(auto &rc : nation) | |
rc = tolower(rc); | |
std::cout<<"lower: "<<nation<<std::endl; | |
std::cout<<"test range for done.\n"; | |
std::cout<<"test divide:\n"; | |
std::cout<<"10 / 3 = "<<(10 / 3)<<"\n"; | |
std::cout<<"-10 / 3 = "<<(-10 / 3)<<"\n"; | |
std::cout<<"-10 / -3 = "<<(-10 / (-3))<<"\n"; | |
std::cout<<"10 % 3 = "<<(10 % 3)<<"\n"; | |
std::cout<<"-10 % 3 = "<<(-10 % 3)<<"\n"; | |
std::cout<<"-10 % -3 = "<<(-10 % (-3))<<"\n"; | |
std::cout<<"10 % -3 = "<<(10 % (-3))<<"\n"; | |
std::cout<<"test divide done.\n"<<std::endl; | |
std::cout<<"test trailing return type:\n"; | |
int (*arr1)[5] = dummy_ret1(1); | |
std::cout<<(*arr1)[0]<<'\t'<<(*arr1)[4]<<std::endl; | |
int (*arr2)[5] = dummy_ret2(2); | |
std::cout<<(*arr2)[0]<<'\t'<<(*arr2)[4]<<std::endl; | |
std::cout<<"test trailing return type done.\n"; | |
std::cout<<"test string filename:\n"; | |
std::string filename = "regex.cpp"; | |
std::ifstream in(filename); | |
std::string head_ctx; | |
in>>head_ctx; | |
std::cout<<head_ctx<<std::endl; | |
std::cout<<"test string filename done.\n"<<std::endl; | |
std::cout<<"test str number cvt:\n"; | |
int age = 15; | |
double weight = 137.5; | |
std::string str_age = std::to_string(age); | |
std::string str_weight = std::to_string(weight); | |
std::cout<<"str age: "<<str_age<<"\tstr weight: "<<str_weight<<std::endl; | |
int int_age = std::stoi(str_age); | |
double d_weight = std::stod(str_weight); | |
std::cout<<"int age: "<<int_age<<"\tdouble weight: "<<d_weight<<std::endl; | |
std::cout<<"test str number cvt done.\n"<<std::endl; | |
std::cout<<"test bind:\n"; | |
auto add5 = std::bind(add_int, std::placeholders::_1, 5); | |
std::cout<<"add5(6): "<<add5(6)<<std::endl; | |
std::cout<<"test bind done.\n"<<std::endl; | |
std::cout<<"test range for of dynamic array:\n"; | |
int *darr = new int[5]{0, 1, 2, 3, 4}; | |
// wrong. dynamic array don't has a begin method, | |
// so we can't use range for here. | |
//for(auto i : darr) | |
// std::cout<<i<<'\t'; | |
for(size_t i = 0; i < 5; i++) | |
std::cout<<darr[i]<<'\t'; | |
std::cout<<'\n'; | |
std::cout<<"test range for of dynamic array done.\n"; | |
std::cout<<"test explicit type cvt:\n"; | |
OtherType c(10); | |
//int i = c + 10; // wrong. can't implicit cvt c to int. | |
int j = static_cast<int>(c) + 10; | |
std::cout<<"OtherType(10) + 10: "<<j<<"\n"; | |
if(c) | |
{ | |
std::cout<<"OtherType can be cvt to bool implicitly in if clause.\n"; | |
} | |
std::cout<<"test explicit type cvt done.\n"<<std::endl; | |
std::cout<<"test inline namespace:\n"; | |
std::cout<<"inline vals: "<<inline_val1<<'\t'<<inline_val2<<std::endl; | |
//std::cout<<"normal vals: "<<normal_val3<<std::endl; | |
std::cout<<"normal vals: "<<NormalSpace::normal_val3<<std::endl; | |
std::cout<<"test inline namespace done.\n"<<std::endl; | |
std::cout<<"test scoped enum:\n"; | |
enum class number {one, two, three}; | |
enum nation {CHN, USA, FRA}; | |
enum nation n1 = CHN; | |
//enum nation n2 = nation::USA; | |
std::cout<<"unscoped enum: "<<n1<<'\t'<<'\n'; | |
//number num1 = one; | |
number num2 = number::two; | |
std::cout<<"scoped enum: "<<(int)num2<<'\n'; | |
std::cout<<"test scoped enum done.\n"; | |
std::cout<<"test enum type declare:\n"; | |
enum long_enum | |
{ | |
firstl = LLONG_MAX - 1, | |
secondl = ULLONG_MAX, | |
}; | |
enum longlong_enum : long long | |
{ | |
firstll = LLONG_MAX - 1, | |
secondll = LLONG_MAX | |
//secondll = ULLONG_MAX | |
}; | |
std::cout<<firstl<<'\n'<<secondl<<'\n'; | |
std::cout<<firstll<<'\n'<<secondll<<'\n'; | |
std::cout<<"test enum type declare done.\n"; | |
} |