C++ 11 新特性之杂项

这是C++11新特性介绍的第十一部分,涉及到一些不好归类的新特性。


不想看toy code的读者可以直接拉到文章最后看这部分的总结。


类型别名声明


类似typedef,新标准中可以使用using为类型声明一个别名(alias)。
  1. std::cout<<"test using alias:\n";
  2. using HT = double;
  3. using NAME = std::string;
  4. HT h = 1.78;
  5. NAME name = "Robert";
  6. std::cout<<name<<"'s height is "<<h<<std::endl;
  7. std::cout<<"test using alias done.\n"<<std::endl;
复制代码



range for


range for语句在之前的章节中已经见识过了:


  1. std::cout<<"test range for:\n";
  2. std::string nation = "CHINA";
  3. for(auto c : nation)
  4.         std::cout<<c<<" ";
  5. std::cout<<"\n";
  6. for(auto &rc : nation)
  7.         rc = tolower(rc);
  8. std::cout<<"lower: "<<nation<<std::endl;
  9. std::cout<<"test range for done.\n";
复制代码



这里需要注意的是,在第二个例子中,range for语句中可以直接使用引用,从而修改被迭代遍历的对象本身。


另外,range for不能用于动态分配内存的数组,因为动态分配的内存中没有begin、end方法可供调用。
  1. std::cout<<"test range for of dynamic array:\n";
  2. int *darr = new int[5]{0, 1, 2, 3, 4};
  3. // wrong. dynamic array don't has a begin method,
  4. // so we can't use range for here.
  5. //for(auto i : darr)         
  6. //        std::cout<<i<<'\t';
  7. for(size_t i = 0; i < 5; i++)
  8.         std::cout<<darr[i]<<'\t';
  9. std::cout<<'\n';
  10. std::cout<<"test range for of dynamic array done.\n";
复制代码



新的除法舍入规则


新标准中,重新统一了除法的舍入规则。主要需要留意两数符号不同时的规则:


(-x) / y = x / (-y) = – (x / y)
x % (-y) = x % y
(-x) % y = – (x % y)
  1. std::cout<<"test divide:\n";
  2. std::cout<<"10 / 3 = "<<(10 / 3)<<"\n";
  3. std::cout<<"-10 / 3 = "<<(-10 / 3)<<"\n";
  4. std::cout<<"-10 / -3 = "<<(-10 / (-3))<<"\n";
  5. std::cout<<"10 % 3 = "<<(10 % 3)<<"\n";
  6. std::cout<<"-10 % 3 = "<<(-10 % 3)<<"\n";
  7. std::cout<<"-10 % -3 = "<<(-10 % (-3))<<"\n";
  8. std::cout<<"10 % -3 = "<<(10 % (-3))<<"\n";
  9. std::cout<<"test divide done.\n"<<std::endl;
复制代码

尾置返回类型


之前,我们也见识过尾置返回类型和decltype的配合使用。有时,采用尾置返回类型,代码的可读性更高。
  1. int (*dummy_ret1(int i))[5]
  2. {
  3.         static int ret1[5] = {i, i*2, i*3, i*4, i*5};
  4.         int(*pret)[5] = &ret1;
  5.         return pret;
  6. }

  7. auto dummy_ret2(int i) -> int (*)[5]
  8. {
  9.         static int ret2[5] = {i+1, i+2, i+3, i+4, i+5};
  10.         int(*pret)[5] = &ret2;
  11.         return pret;
  12. }

  13. std::cout<<"test trailing return type:\n";
  14. int (*arr1)[5] = dummy_ret1(1);
  15. std::cout<<(*arr1)[0]<<'\t'<<(*arr1)[4]<<std::endl;
  16. int (*arr2)[5] = dummy_ret2(2);
  17. std::cout<<(*arr2)[0]<<'\t'<<(*arr2)[4]<<std::endl;
  18. std::cout<<"test trailing return type done.\n";
复制代码

使用字符串作为文件名


在新标准中,可以直接使用string作为文件名进行文件流处理,而不必要求C风格字符数组。
  1. std::cout<<"test string filename:\n";
  2. std::string filename = "regex.cpp";
  3. std::ifstream in(filename);
  4. std::string head_ctx;
  5. in>>head_ctx;
  6. std::cout<<head_ctx<<std::endl;
  7. std::cout<<"test string filename done.\n"<<std::endl;
复制代码

字符串和数值的转换


新标准中,添加了多个函数用于string和数值之间的转换。
  1. std::cout<<"test str number cvt:\n";
  2. int age = 15;
  3. double weight = 137.5;
  4. std::string str_age = std::to_string(age);
  5. std::string str_weight = std::to_string(weight);
  6. std::cout<<"str age: "<<str_age<<"\tstr weight: "<<str_weight<<std::endl;
  7. int int_age = std::stoi(str_age);
  8. double d_weight = std::stod(str_weight);
  9. std::cout<<"int age: "<<int_age<<"\tdouble weight: "<<d_weight<<std::endl;
  10. std::cout<<"test str number cvt done.\n"<<std::endl;
复制代码

bind 函数


新标准中,提供了功能更强大的参数绑定函数bind,用于替换原有的bind1st和bind2nd。


  1. int add_int(int a, int b)
  2. {
  3.         return a + b;
  4. }

  5. std::cout<<"test bind:\n";
  6. auto add5 = std::bind(add_int, std::placeholders::_1, 5);
  7. std::cout<<"add5(6): "<<add5(6)<<std::endl;
  8. std::cout<<"test bind done.\n"<<std::endl;
复制代码

std::placeholders::_1表示占位符,指代第1个参数,等待后续真正调用时由用户传入。


显式类型转换


新标准中,可以指定一个类型转换为显式(explicit)的。指定为显式的类型转换,不能再进行隐式转换。
  1. class OtherType
  2. {
  3. public:
  4.         OtherType(int i) : val(i){}
  5.         explicit operator int() {return val;}
  6.         explicit operator bool() {return val != 0;}
  7. private:
  8.         int val;
  9. };

  10. std::cout<<"test explicit type cvt:\n";
  11. OtherType c(10);
  12. //int i = c + 10; // wrong. can't implicit cvt c to int.
  13. int j = static_cast<int>(c) + 10;
  14. std::cout<<"OtherType(10) + 10: "<<j<<"\n";
  15. if(c)
  16. {
  17.         std::cout<<"OtherType can be cvt to bool implicitly in if clause.\n";
  18. }
  19. std::cout<<"test explicit type cvt done.\n"<<std::endl;
复制代码



这其中有一个例外,即,即使指定一个类型和bool类型之间的转换是显式的,在if语句中,也仍然可以执行隐式类型转换。


内联命名空间


新标准中引入了内联命名空间。内联命名空间内的名字可以不加命名空间名字前缀,直接在外层命名空间中使用。这为我们设置一个默认的命名空间提供了方便。
  1. inline namespace InlineSpace
  2. {
  3.         int inline_val1 = 1;
  4. }

  5. namespace InlineSpace
  6. {
  7.         int inline_val2 = 2;
  8. }

  9. namespace NormalSpace
  10. {
  11.         int normal_val3 = 3;
  12. }

  13. std::cout<<"test inline namespace:\n";
  14. std::cout<<"inline vals: "<<inline_val1<<'\t'<<inline_val2<<std::endl;
  15. //std::cout<<"normal vals: "<<normal_val3<<std::endl;
  16. std::cout<<"normal vals: "<<NormalSpace::normal_val3<<std::endl;
  17. std::cout<<"test inline namespace done.\n"<<std::endl;
复制代码



只需在第一次声明内联命名空间时加上inline关键字,之后就可以省略了。


限定作用域的 enum


新标准中,可以通过enum class foo这样的形式定义一个限定作用域的枚举,其中的枚举变量在作用域之外不可见。
  1. std::cout<<"test scoped enum:\n";
  2. enum class number {one, two, three};
  3. enum nation {CHN, USA, FRA};
  4. enum nation n1 = CHN;
  5. //enum nation n2 = nation::USA;
  6. std::cout<<"unscoped enum: "<<n1<<'\t'<<'\n';
  7. //number num1 = one;
  8. number num2 = number::two;
  9. std::cout<<"scoped enum: "<<(int)num2<<'\n';
  10. std::cout<<"test scoped enum done.\n";
复制代码

其中,one、two、three就只能在number限定的作用域中可见,而CHN、USA、FRA就没有这个限制。


指定枚举的数据类型


新标准中,可以指定枚举的数据类型为除了int之外的其他整数类型。
  1. std::cout<<"test enum type declare:\n";
  2. enum long_enum
  3. {
  4.         firstl = LLONG_MAX - 1,
  5.         secondl = ULLONG_MAX,
  6. };
  7. enum longlong_enum : long long
  8. {
  9.         firstll = LLONG_MAX - 1,
  10.         secondll = LLONG_MAX
  11.         //secondll = ULLONG_MAX
  12. };
  13. std::cout<<firstl<<'\n'<<secondl<<'\n';
  14. std::cout<<firstll<<'\n'<<secondll<<'\n';
  15. std::cout<<"test enum type declare done.\n";
复制代码

输出


整个测试程序的输出结果如下:


  1. test using alias:
  2. Robert's height is 1.78
  3. test using alias done.

  4. test range for:
  5. C H I N A 
  6. lower: china
  7. test range for done.
  8. test divide:
  9. 10 / 3 = 3
  10. -10 / 3 = -3
  11. -10 / -3 = 3
  12. 10 % 3 = 1
  13. -10 % 3 = -1
  14. -10 % -3 = -1
  15. 10 % -3 = 1
  16. test divide done.

  17. test trailing return type:
  18. 1       5
  19. 3       7
  20. test trailing return type done.
  21. test string filename:
  22. #include
  23. test string filename done.

  24. test str number cvt:
  25. str age: 15     str weight: 137.500000
  26. int age: 15     double weight: 137.5
  27. test str number cvt done.

  28. test bind:
  29. add5(6): 11
  30. test bind done.

  31. test range for of dynamic array:
  32. 0       1       2       3       4
  33. test range for of dynamic array done.
  34. test explicit type cvt:
  35. OtherType(10) + 10: 20
  36. OtherType can be cvt to bool implicitly in if clause.
  37. test explicit type cvt done.

  38. test inline namespace:
  39. inline vals: 1  2
  40. normal vals: 3
  41. test inline namespace done.

  42. test scoped enum:
  43. unscoped enum: 0
  44. scoped enum: 1
  45. test scoped enum done.

  46. test enum type declare:
  47. 9223372036854775806
  48. 18446744073709551615
  49. 9223372036854775806
  50. 9223372036854775807
  51. test enum type declare done.
复制代码

总结


类似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";
   
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值