C++ 11:花括号或等号初始化器(initializers)
花括号或等号初始化器(initializers)
变量的初始化会在构造时提供变量的初始值。
初始值可以由声明符或 new 表达式的初始化器部分提供。在函数调用时也会发生:函数形参及函数返回值也会被初始化。
对于每个声明符,初始化器必须是下列之一:
( 表达式列表 ) // 括号中的以逗号分隔的含有任意表达式和花括号初始化器列表的列表
= 表达式 // 等号后面跟着一个表达式
{ 初始化器列表 } // 花括号初始化器列表:以逗号分隔且可以为空的含有表达式和其他花括号初始化器列表的列表
根据上下文,初始化器可以调用:
123456std::string s{}; // 值初始化std::string s("hello"); // 直接初始化std::string s = "hello"; // 复制初始化std::string s{'a', 'b', 'c'}; // 列表初始化char a[3] = {'a', & ...
C++ 11:委托与继承的构造函数 (delegating and inherited constructors)
委托构造函数
如果类自身的名字在初始化器列表中作为 类或标识符 出现,那么该列表只能由这一个成员初始化器组成;这种构造函数被称为委托构造函数(delegating constructor),而构造函数列表的仅有成员所选择的构造函数是目标构造函数。
此时首先由重载决议选择目标构造函数并予以执行,然后控制返回到委托构造函数并执行其函数体。
委托构造函数不能递归。
123456class Foo{public: Foo(char x, int y) {} Foo(int y) : Foo('a', y) {} // Foo(int) 委托到 Foo(char, int)};
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950#include <fstream>#include <string>#include <mutex> stru ...
C++ 11:字面类型(literal types)
字面类型(literal types)
指明一个类型为字面类型。字面类型是 constexpr 变量所拥有的类型,且能通过 constexpr 函数构造、操作及返回它们。
注意:标准中并没有定义具有这个名字的具名要求。这是核心语言所定义的一种类型类别。将它作为具名要求包含于此只是为了保持一致性。
1234567891011121314151617181920212223242526272829303132333435363738#include <iostream>#include <stdexcept> class conststr{ const char* p; std::size_t sz;public: template<std::size_t N> constexpr conststr(const char(&a)[N]) : p(a), sz(N - 1) {} constexpr char operator[](std::size_t n) const ...
C++ 11:初始化列表(list initialization)
初始化列表(list initialization)
从 花括号初始化器列表 列表初始化对象。
聚合体直接从同类型的单元素 花括号初始化器列表 进行复制/移动初始化,但非聚合体首先考虑 initializer_list 构造函数:
1234567891011121314151617struct X {}; // 聚合体 struct Q // 非聚合体{ Q() = default; Q(Q const&) = default; Q(std::initializer_list<Q>) {}}; int main(){ X x; X x2 = X{x}; // 复制构造函数(非聚合初始化) Q q; Q q2 = Q{q}; // 初始化器列表构造函数(非复制构造函数)}
1234567891011121314151617181920212223242526272829303132333435363 ...
C++ 11:常量表达式(constexpr)
constexpr 说明符
constexpr - 指定变量或函数的值可以在常量表达式中出现
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#include <iostream>#include <stdexcept> // C++11 constexpr 函数使用递归而非迭代// (C++14 constexpr 函数可使用局部变量和循环)constexpr int factorial(int n){ return n <= 1 ? 1 : (n * factorial(n - 1));} // 字面类class conststr{ const char* p; std::size_t sz;public: template<std::size_t N> constexpr conststr(const char(& ...
C++ 11:移动赋值运算符(move assignment operators)
移动赋值运算符
类 T 的移动赋值运算符是名为 operator= 的非模板非静态成员函数,它接受恰好一个 T&&、const T&&、volatile T&& 或 const volatile T&& 类型的形参。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include <string>#include <iostream>#include <utility> struct A{ std::string s; A() : s("测试") {} A(const A& o) : s(o.s) { std::cout << "移动失败!\n& ...
C++ 11:有作用域枚举(scoped enums)
有作用域枚举
1234567891011enum struct|class 名字 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... }// 声明底层类型为 int 的有作用域枚举类型(关键词 class 与 struct 完全等价)enum struct|class 名字 : 类型 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... }// 声明底层类型为 类型 的有作用域枚举类型enum struct|class 名字 ;// 底层类型为 int 的有作用域枚举类型的不可见枚举声明enum struct|class 名字 : 类型 ;// 底层类型为 类型 的有作用域枚举类型的不可见枚举声明
每个 枚举项 都成为该枚举的类型(即 名字)的具名常量,它被该枚举的作用域所包含,且可用作用域解析运算符访问。没有从有作用域枚举项到整数类型的隐式转换,尽管 static_cast 可以用来获得枚举项的数值。
1234567891011121314151617enum class Color { red, gre ...
C++ 11:移动构造函数(move constructors)
移动构造函数
类 T 的移动构造函数是非模板构造函数,它的首个形参是 T&&、const T&&、volatile T&& 或 const volatile T&&,且没有其他形参,或剩余形参均有默认值。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869#include <string>#include <iostream>#include <iomanip>#include <utility> struct A{ std::string s; int k; A() : s("测试"), k(-1) {} A(const A& o) : s(o.s), k(o.k) { std ...
C++ 11:右值引用(rvalue references)
声明具名变量为引用,即既存对象或函数的别名。
左值引用声明符:声明 S& D; 是将 D 声明为 声明说明符序列 S 所确定的类型的左值引用。
右值引用声明符:声明 S&& D; 是将 D 声明为 声明说明符序列 S 所确定的类型的右值引用。
引用必须被初始化为指代一个有效的对象或函数:见引用初始化。
不存在 void 的引用,也不存在引用的引用。
引用不是对象;它们不必占用存储,尽管编译器会在需要实现所需语义(例如,引用类型的非静态数据成员通常会增加类的大小,量为存储内存地址所需)的情况下分配存储。
因为引用不是对象,所以不存在引用的数组,不存在指向引用的指针,不存在引用的引用:
123int& a[3]; // 错误int&* p; // 错误int& &r; // 错误
引用折叠
通过模板或 typedef 中的类型操作可以构成引用的引用,此时适用引用折叠(reference collapsing)规则:右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用:
12345678typedef int&am ...
C++ 11:返回类型后置(trailing return type)
123456789101112131415161718192021222324252627// auto用于占位符,真正的返回值在后面定义// 返回指向 f0 的指针的函数auto fp11() -> void(*)(const std::string&){ return f0;} // 返回指向 f0 的指针的函数,C++11 前的风格void (*fp03())(const std::string&){ return f0;}// 这样的语法用于在编译时返回类型还不确定的场合// 比如有模版的场合中,两个类型相加的最终类型只有运行时才能确定template<class Lhs, class Rhs>auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) { return lhs + rhs;}int main() { cout << add ...