概述
语言特性
__has_cpp_attribute
- 检查是否存在由属性标记命名的属性,例如deprecated等
#include <iostream>
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(deprecated)
#define DEPRECATED(msg) [[deprecated(msg)]]
#endif
#endif
#ifndef DEPRECATED
#define DEPRECATED
#endif
DEPRECATED("the func has been deprecated")
void func()
{
std::cout << "test";
}
int main()
{
func();
getchar();
return 0;
}
operator<=>
- 用于两个相同的值进行大小相等判断
#include <compare>
#include <iostream>
int main()
{
double foo = -0.0;
double bar = 0.0;
auto res = foo <=> bar;
if (res < 0)
std::cout << "-0 is less than 0";
else if (res > 0)
std::cout << "-0 is greater than 0";
else // (res == 0)
std::cout << "-0 and 0 are equal";
}
//输出结果:-0 and 0 are equal
聚合初始化
- 可通过结构体变量名指定初始化
struct test
{
int a;
int b;
};
int main()
{
test t{ .b = 10, .a = 20 };//error
test t{ .a = 10, .b = 20 };
return 0;
}
char8_t
- 新增的宽字符串
[[no_unique_address]]
- 适用于在不是位字段的非静态数据成员的声明中声明的名称,编译器可以优化它以不占用空间
#include <iostream>
struct Empty {}; // empty class
struct X {
int i;
Empty e;
};
struct Y {
int i;
[[no_unique_address]] Empty e;
};
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
struct W {
char c[2];
[[no_unique_address]] Empty e1, e2;
};
[[likely]] & [[unlikely]]
- 允许编译器针对以下情况进行优化:包含该语句的执行路径比不包含此类语句的任何替代执行路径更有可能
if(x)[[likely]]
{
std::cout << 1;
}
else[[unlikely]]
{
std::cout << 2;
}
consteval & constinit
- consteval- 指定一个函数是一个立即函数,即每次调用该函数都必须产生一个编译时常量s
constexpr unsigned factorial(unsigned n) {
return n < 2 ? 1 : n * factorial(n - 1);
}
consteval unsigned combination(unsigned m, unsigned n) {
return factorial(n) / factorial(m) / factorial(n - m);
}
static_assert(factorial(6) == 720);
static_assert(combination(4,8) == 70);
int main(int argc, const char*[]) {
constexpr unsigned x{factorial(4)};
std::cout << x << 'n';
[[maybe_unused]]
unsigned y = factorial(argc); // OK
// unsigned z = combination(argc, 7); // error: 'argc' 不是一个常量表达式
}
- constinit- 断言一个变量有静态初始化,即零初始化和常量初始化,否则程序是病态的
const char *g() { return "dynamic initialization"; }
constexpr const char *f(bool p) { return p ? "constant initializer" : g(); }
constinit const char *c = f(true); // OK
// constinit const char *d = f(false); // error
Coroutines
- 协程是一个可以暂停执行以便稍后恢复的函数。协程是无堆栈的:它们通过返回给调用者来暂停执行,并且恢复执行所需的数据与堆栈分开存储。这允许异步执行的顺序代码。目前C++20并没有封装好的类库,使用还是比较繁琐,可以等C++23看看
#include <iostream>
#include <experimental/coroutine>
//编译环境 vs2017
struct generator
{
struct promise_type;
using handle = std::experimental::coroutine_handle<promise_type>;
struct promise_type
{
static auto get_return_object_on_allocation_failure() { return generator(nullptr); }
auto get_return_object() { return generator{ handle::from_promise(*this) }; }
auto initial_suspend() { return std::experimental::suspend_always{}; }
auto final_suspend() { return std::experimental::suspend_always{}; }
void unhandled_exception() { std::terminate(); }
void return_void() {}
//auto return_value(int value) { return value; }
};
bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
int current_value() { return coro.promise().current_value; }
generator(generator const &) = delete;
generator(generator &&rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
~generator() { if (coro) coro.destroy(); }
private:
generator(handle h) : coro(h) {}
handle coro;
};
generator f()
{
std::cout << "hello";
co_await std::experimental::suspend_always();
std::cout << "world";
}
int main()
{
auto ret = f();
while (ret.move_next())
{
std::cout << " ";
}// hello world
getchar();
return 0;
}
Modules
- 模块是一种跨翻译单元共享声明和定义的语言功能。它们是一些头文件用例的替代方案
// A.cpp
export module A;
export import :B;
import :C;
export char const* World() {
return WorldImpl();
}
// A-B.cpp
export module A:B;
export char const* Hello() { return "Hello"; }
// A-C.cpp
module A:C;
char const* WorldImpl() { return "World"; }
// main.cpp
import A;
import <iostream>;
int main()
{
std::cout << Hello() << ' ' << World() << 'n';
}
Concepts
- 类模板、函数模板和非模板函数(通常是类模板的成员)可能与一个约束相关联,该约束指定了对模板参数的要求,可用于选择最合适的函数重载和模板特化,更多详情查看
template<typename T>
concept Addable = requires (T obj) {{obj + obj}->std::same_as<T>;};//约束a+b的类型必须和T类型一致
T add(T a, T b)
{
return a + b;
}
新增标准库函数
std::format
- 替代sprintf
#include <format>
#include <cassert>
int main() {
std::string message = std::format("The answer is {}.", 42);//The answer is 42.
std::string buffer;
std::format_to(std::back_inserter(buffer), "Hello, C++{}!n", "20");//向后插入,Hello, C++20!
auto buff = "{0}:{1}:{2}";
auto h = 17;
auto m = 46;
auto s = 55;
auto size = std::format_size(buff, h, m, s);
std::string ti;
ti.resize(size);
std::format_to_n(const_cast<char*>(ti.c_str()), ti.size(), buff, h, m, s);
ti.push_back('