使用auto
自动类型推断,顾名思义,就是编译器能够根据表达式的类型,自动决定变量的类型(从 C++14 开始,还有函数的返回类型),不再需要程序员手工声明。
但需要说明的是,auto 并没有改变 C++ 是静态类型语言这一事实——使用 auto 的变量(或函数返回 值)的类型仍然是编译时就确定了,只不过编译器能自动帮你填充而已。
自动类型推断不仅降低了代码的啰嗦程度,也提高了代码的抽象性,使我 们可以用更少的代码写出通用的功能。
auto 实际使用的规则类似于函数模板参数的推导规则。
当写了一个含 auto 的表 达式时,相当于把 auto 替换为模板参数的结果。举具体的例子:
auto a = expr; 意味着用 expr 去匹配一个假想的 template f(T) 函数模板,结果为值类型。
const auto& a = expr; 意味着用 expr 去匹配一个假想的 template f(const T&) 函数模板,结果为常左值引用类型。
auto&& a = expr; 意味着用 expr 去匹配一个假想的 template f(T&&) 函数模板,根据 [第 3 讲] 中我们讨论过的转发引用和引用坍缩规则,结果是 一个跟 expr 值类别相同的引用类型。
decltype
decltype 的用途是获得一个表达式的类型,结果可以跟类型一样使用。它有两基本用 法:
1. decltype(变量名) 可以获得变量的精确类型。
2. decltype(表达式) (表达式不是变量名,但包括 decltype((变量名)) 的情况)可以获得表达式的引用类型;
除非表达式的结果是个纯右值(prvalue),此时结果仍然是值类型。
例子:
如果我们有 int a;,那么:
decltype(a) 会获得 int(因为 a 是 int)。
decltype((a)) 会获得 int&(因为 a 是 lvalue,情况二表达式情况)。
decltype(a + a) 会获得 int(因为 a + a 是 prvalue)。
decltype(auto)
通常情况下,能写 auto 来声明变量肯定是件比较轻松的事。但这儿有个限制,需要在写 下 auto 时就决定你写下的是个引用类型还是值类型。
根据类型推导规则,auto 是值类 型,auto& 是左值引用类型,auto&& 是转发引用(可以是左值引用,也可以是右值引 用)。
使用 auto 不能通用地根据表达式类型来决定返回值的类型。
不过, decltype(expr) 既可以是值类型,也可以是引用类型。因此,我们可以这么写:
decltype(expr) a = expr;
这种写法明显不能让人满意,特别是表达式很长的情况(而且,任何代码重复都是潜在的问 题)。为此,C++14 引入了 decltype(auto) 语法。对于上面的情况,我们只需要像下 面这样写就行了。
decltype(auto) a = expr;
这种代码主要用在通用的转发函数模板中:可能根本不知道你调用的函数是不是会返回一 个引用。这时使用这种语法就会方便很多。
函数返回值类型推断
从 C++14 开始,函数的返回值也可以用 auto 或 decltype(auto) 来声明了。同样的, 用 auto 可以得到值类型,用 auto& 或 auto&& 可以得到引用类型;
而用 decltype(auto) 可以根据返回表达式通用地决定返回的是值类型还是引用类型。
auto foobar(参数) { //函数体 } //编译加上-std=c++14
类模板的模板参数推导
结构化绑定
列表初始化
统一初始化
。。。没看懂到总结的程度,待补充。
类数据成员的默认初始化
class Complex { public: Complex() : re_(0) , im_(0) {} Complex(float re) : re_(re), im_(0) {} Complex(float re, float im) : re_(re) , im_(im) {} … private: float re_;
float im_;
};
C++11 增加了一个语法,允许 在声明数据成员时直接给予一个初始化表达式。这样,当且仅当构造函数的初始化列表中不 包含该数据成员时,这个数据成员就会自动使用初始化表达式进行初始化。
假设由于某种原因,我们不能使用缺省参数来简化构造函数,可以用什么方式来优化上 面这个代码呢?
class Complex { public: Complex() {} Complex(float re) : re_(re) {} Complex(float re, float im) : re_(re) , im_(im) {} private: float re_{0}; float im_{0}; }
第一个构造函数没有任何初始化列表,所以类数据成员的初始化全部由默认初始化完成, re_ 和 im_ 都是 0。第二个构造函数提供了 re_ 的初始化,im_ 仍由默认初始化完成。第 三个构造函数则完全不使用默认初始化。
字面量
C++11 引入了自定义字面量,可以使用 operator"" 后缀 来将用户提供的字面量转换成 实际的类型。C++14 则在标准库中加入了不少标准字面量。
用户定义字面量 (C++11 起) - cppreference.com
标准库中定义了下列字面量运算符:
定义于内联命名空间
std::literals::complex_literals |
|
表示纯虚数的 std::complex 字面量 (函数) |
|
定义于内联命名空间
std::literals::chrono_literals |
|
(C++14)
|
表示小时的 std::chrono::duration 字面量 (函数) |
(C++14)
|
表示分钟的 std::chrono::duration 字面量 (函数) |
(C++14)
|
表示秒的 std::chrono::duration 字面量 (函数) |
(C++14)
|
表示毫秒的 std::chrono::duration 字面量 (函数) |
(C++14)
|
表示微秒的 std::chrono::duration 字面量 (函数) |
(C++14)
|
表示纳秒的 std::chrono::duration 字面量 (函数) |
(C++20)
|
表示特定年的 std::chrono::year 字面量 (函数) |
(C++20)
|
表示月内日期的 std::chrono::day 字面量 (函数) |
定义于内联命名空间
std::literals::string_literals |
|
(C++14)
|
转换字符数组字面量为 basic_string (函数) |
定义于内联命名空间
std::literals::string_view_literals |
|
(C++17)
|
创建一个字符数组字面量的字符串视图 (函数) |
样例:
#include <chrono> #include <complex> #include <iostream> #include <string> #include <thread> using namespace std; int main() { cout << "i * i = " << 1i * 1i << endl; cout << "Waiting for 500ms" << endl; this_thread::sleep_for(500ms); cout << "Hello world"s.substr(0, 5) << endl; }
输出:
i * i = (-1,0) Waiting for 500ms Hello
要在自己的类里支持字面量也相当容易,唯一的限制是非标准的字面量后缀必须以下划线 _ 打头。
自己定义字面量:
struct length { double value; enum unit { metre, kilometre, millimetre, centimetre, inch, foot, yard, mile, }; static constexpr double factors[] = { 1.0, 1000.0, 1e-3, 1e-2, 0.0254, 0.3048, 0.9144, 1609.344 }; explicit length(double v, unit u = metre) { value = v * factors[u]; } };
length operator+(length lhs, length rhs)
{
return length(lhs.value + rhs.value);
}
可以手写 length(1.0, length::metre) 这样的表达式,但估计大部分开发人员 都不愿意这么做吧。
反过来,如果我们让开发人员这么写,大家应该还是基本乐意的:
1.0_m + 10.0_cm
要允许上面这个表达式,我们只需要提供下面的运算符即可:
length operator"" _m(long double v) { return length(v, length::metre); } length operator"" _cm(long double v) { return length(v, length::centimetre); }
静态断言
C++98 的 assert 允许在运行时检查一个函数的前置条件是否成立。没有一种方法允许开 发人员在编译的时候检查假设是否成立。
C++11 直接从语言层面提供了静态断言机制,不仅能输出更好的 信息,而且适用性也更好,可以直接放在类的定义中,而不像之前用的特殊技巧只能放在函 数体里。
static_assert(编译期条件表达式, 可选输出信息);
for example:
static_assert((alignment & (alignment - 1)) == 0, "Alignment must be power of two");
default 和 delete 成员函数
override 和 final 说明符
原文链接: https://www.cnblogs.com/JohnsonQ/p/17022648.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/309501
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!