C++11 FAQ


auto – 从初始化中推断数据类型 当数据类型未知或不便书写时,使用auto可让编译器自动根据用以初始化变量的表达式类型来推导变量类型。考虑如下代码:
template<class T > void printall(const vector< T>& v)
{
        // 根据v.begin()的返回值类型自动推断p的数据类型
        for ( auto p = v.begin(); p != v.end(); ++p)
              cout << *p << “n”;
}
枚举类——具有类域和强类型的枚举 枚举类主要用来解决传统的C++枚举的三个问题:
  • 传统C++枚举会被隐式转换为int,这在那些不应被转换为int的情况下可能导致错误
  • 传统C++枚举的每一枚举值在其作用域范围内都是可见的,容易导致名称冲突(同名冲突)
  • 不可以指定枚举的底层数据类型,这可能会导致代码不容易理解、兼容性问题以及不可以进行前向声明
          enum Alert { green , yellow , election , red };        // 传统枚举
        enum class Color { red, blue };                     // 新的具有类域和强类型的枚举类
                                                            // 它的枚举值在类的外部是不可直接访问的,需加“类名::”
                                                             // 不会被隐式转换成int
        enum class TrafficLight { red , yellow , green };
        Alert a = 7;                                        // 错误,传统枚举不是强类型的,a没有数据类型
        Color c = 7;                                        // 错误,没有int到Color的隐式转换
        int a2 = red;                                       // 正确,Alert被隐式转换成int
        int a3 = Alert:: red;                                // 在 C++98中是错误的,但是在C++11中正确的
        int a4 = blue;                                      // 错误,blue并没有在类域中
        int a5 = Color:: blue;                               // 错误,没有Color到int的默认转换         Color a6 = Color:: blue;                             // 正确   正如上面的代码所展示的那样,传统的枚举可以照常工作,但是你现在可以通过提供一个类名来改善枚举的使用,使其成为一个强类型的具有类域的枚举。因为新的具有类名的枚举具有传统的枚举的功能(命名的枚举值),同时又具有了类的一些特点(枚举值作用域处于类域之内且不会被隐式类型转换成int),所以我们将其称为枚举类(enum class)。 因为可以指定枚举的底层数据类型,所以可以进行简单的互通操作以及保证枚举值所占的字节大小:
enum class Color : char { red , blue };                                    // 紧凑型表示(一个字节)
enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };          // C11中我们可以指定枚举值的底层数据类型大小
同时,由于能够指定枚举值的底层数据类型,所以前向声明得以成为可能:
enum class Color_code : char ;     // (前向) 声明
void foobar(Color_code * p);        // 使用
// ...
// 定义
enum class Color_code : char { red , yellow , green , blue };
常量表达式(constexpr) — 一般化的受保证的常量表达式 常量表达式机制是为了:
  • 提供一种更加通用的常量表达式
  • 允许用户自定义的类型成为常量表达式
  • 提供了一种保证在编译期完成初始化的方法(可以在编译时期执行某些函数调用)

考虑下面这段代码:         enum Flags { good = 0, fail = 1, bad = 2, eof = 4 };
       constexpr int operator|( Flags f1, Flags f2)
       {
               return Flags( int( f1) | int( f2));
       }
        void f( Flags x)
       {
               switch ( x) {
               case bad:         /* … */ break ;
               case eof:         /* … */ break ;
               case bad | eof /* … */ break ;
               default:          /* … */ break ;
              }
       } 在这里,常量表达式关键字constexpr表示这个重载的操作符“|”只应包含形式简单的运算,如果它的参数本身就是常量 ,那么这个操作符应该在编译时期就应该计算出它的结果来。(译注: 我们都知道,switch的分支条件要求常量,而使用constexpr关键字重载操作符“|”之后,虽然“bad|eof”是一个表达式,但是因为这两个参数都是常量,在编译时期,就可以计算出它的结果,因而也可以作为常量对待。) 除了可以在编译时期被动地计算表达式的值之外,我们希望能够强制要求表达式在编译时期计算其结果值,从而用作其它用途,比如对某个变量进行赋值。当我们在变量声明前加上constexpr关键字之后,可以实现这一功能,当然,它也同时会让这个变量成为常量。         constexpr int x1 = bad | eof;    // ok         void f(Flags f3)        {                // 错误:因为f3不是常量,所以无法在编译时期计算这个表达式的结果值               constexpr int x2 = bad | f3;                int x3 = bad | f3;     // ok,可以在运行时计算        }

需要注意的是,constexpr并不是const的通用版,反之亦然:

  • const主要用于表达“对接口的写权限控制”,即“对于被const修饰的量名(例如const指针变量),不得通过它对所指对象作任何修改”。(但是可以通过其他接口修改该对象)。另外,把对象声明为const也为编译器提供了潜在的优化可能。具体来说就是,如果把一个量声明为const,并且没有其他地方对该量作取址运算,那么编译器通常(取决于编译期实现)会用该量的实际常量值直接替换掉代码中所有引用该量的地方,而不用在最终编译结果中生成对该量的存取指令。
  • constexpr的主要功能则是让更多的运算可以在编译期完成,并能保证表达式在语义上是类型安全的。(译注:相比之下,C语言中#define只能提供简单的文本替换,而不具任何类型检查能力)。与const相比,被constexpr修饰的对象则强制要求其初始化表达式能够在编译期完成计算。之后所有引用该常量对象的地方,若非必要,一律用计算出来的常量值替换。

 

C++11新特性:Lambda函数(匿名函数) 

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

C++11 获取系统时间库函数 time since epoch

C++11中正则表达式测试

更多详情见请继续阅读下一页的精彩内容:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 下一页

相关内容