最近、ISO C ++委員会は、ISO / IEC 14882:2020という名前のC ++ 20標準を正式にリリースしました。
プログラマーとして、私は常に新しい標準がリリースされたのを見て戦いたいと思っています。現在、gcc10.2はいくつかのC ++ 20標準をサポートできます。コンパイルするときは、コンパイラオプション-std = c ++ 2aを使用する必要があります。
制約と概念(制約と概念)
クラステンプレートと関数テンプレートのプログラミングでは、主にテンプレートパラメータを終了および制限するために使用されます。このような制約と制限はコンパイル中に発生し、コンパイルエラーはそれほど不明瞭ではありません。
テンプレートプログラミングでは、テンプレートパラメータのタイプを制限したり、次のような特定の特性を持たせることができます。整数、数値、ブールに制限できるか、ハッシュ特性をサポートする必要があるか、クラスの派生型など。
コンセプトはC ++ 20の非常に重要なコンセプトであり、テンプレートプログラミングはついに質的に改善されました。
コンセプト
Conceptsは、要件の名前付きコレクションです。Conceptsは、名前名で宣言する必要があります。構文は次のとおりです。
template < template-parameter-list >
concept concept-name = constraint-expression;
次のように:
template<typename T>
concept Hashable = requires(T a) {
{
std::hash<T>{
}(a) } -> std::convertible_to<std::size_t>;
};//声明了一个名为Hashable的concept
struct meow {
};
template<Hashable T>
void f(T); // 约束这个T必须满足Hashable concept,否则无法编译通过。
int main() {
f("abc"s); // OK,string是可hash的
f(meow{
}); // Error: meow结构体不是可hash的,当然可以让其支持hash。
}
//
template<typename T>
concept C=sizeof(T)>10;
template<C T>
class test{
};
template<C T>
void func(T t);
制約
制約は、テンプレートの実際のパラメーターの要件を指定するために使用される一連の論理演算とオペランドです。要件式に表示することも、概念の主題として直接表示することもできます。
制約には次の3つのタイプがあります。
- 結合
- 分離
- 原子の制約
次のように:
template<Incrementable T>
void f(T) requires Decrementable<T>;
template<Incrementable T>
void f(T) requires Decrementable<T>; // OK:重声明
必要です
requires
テンプレートパラメータまたは特定のパラメータを制約するために使用されます。
条項が必要
次のように:
template<typename T>
void f(T&&) requires Eq<T>; // 可作为函数声明符的最末元素出现
template<typename T> requires Addable<T> // 或在模板形参列表的右边
T add(T a, T b) {
return a + b; }
キーワードrequiresの後には定数式が続く必要があります(したがって、requires trueとして記述できます)が、その意図は、名前付き概念(上記の例のように)、名前付き概念の結合/分離、またはrequires式を使用することです。 。
式は、次のいずれかの形式である必要があります。
- Swappable、std :: is_integral :: value、(std :: is_object_v &&…)などの基本式、または括弧で囲まれた式
- 演算子&&によって接続された一連の基本式
- 演算子に関連する前述の式のシーケンス||
式が必要
構文は次のとおりです。
requires {
requirement-seq }
requires ( parameter-list(optional) ) {
requirement-seq }
parameter-list-関数宣言に似た正式なパラメーターのコンマ区切りのリストですが、デフォルトの実際のパラメーターは許可されておらず、省略記号で終了することはできません(パッケージ展開が指定されていません)。これらの正式なパラメータには、保存期間、接続、または有効期間がなく、さまざまな要件の策定を支援するためにのみ使用されます。これらの正式なパラメータは、必要なシーケンスを閉じる前にスコープ内にあります。
要件-seq-以下で説明する要件のシーケンス(各要件はセミコロンで終わります)。
require-seqの各要件は、次の4つの項目のいずれかである必要があります。
- 単純な要件
- タイプ要件
- 複合要件
- ネストされた要件
次のように:
template<typename T>
concept Addable = requires (T x) {
x + x; }; // requires 表达式
template<typename T> requires Addable<T> // requires 子句,非 requires 表达式
T add(T a, T b) {
return a + b; }
template<typename T>
requires requires (T x) {
x + x; } // 随即的约束,注意关键字被使用两次
T add(T a, T b) {
return a + b; }
モジュール
コードを論理的に分割するために使用され、コンパイル速度を上げることができ、インポートの順序とは関係ありません(#include
異なる順序によって引き起こされた以前のコンパイルエラーを覚えていますか?)
3つの主要なキーワードがあります。
- モジュール:モジュールを宣言するために使用されます
- export:モジュール、関数、またはクラスをエクスポートするために使用されます
- import:モジュールのインポートに使用されます
以下に示すように:
helloworldモジュールが定義され、hello関数がエクスポートされます
//helloworld.cpp
export module helloworld; // module declaration
import <iostream>; // import declaration
export void hello() {
// export declaration
std::cout << "Hello world!\n";
}
//main.cpp
import helloworld;
int main()
{
hello();
}
Coroutines(coroutines)
コルーチンは、実行を一時停止し、後で実行を再開できる関数です。C++のコルーチンにはスタックがありません(スタックが少ない)。ルーチンを使用すると、非同期コードを簡単に記述できます(同期コードの記述と同様)。
主に3つのキーワードが関係しています。
- co_await
co_awaitは、現在のコルーチンの実行を一時停止し、待機操作が完了するまで実行を継続します。
task<> tcp_echo_server() {
char data[1024];
for (;;) {
std::size_t n = co_await socket.async_read_some(buffer(data)); #与 Python 中的 await 类似
co_await async_write(socket, buffer(data, n));
}
}
上記のコードは、async_read_some()の完了後、次のステートメントの実行を継続し、async_read_some()の実行が完了する前に、実行を一時停止して制御を放棄します。
- co_yield
co_yieldは実行を一時停止し、値を返します。returnとの違いは、co_yieldは値を返しますが、現在の関数は終了しないことです。
generator<int> iota(int n = 0) {
while(true)
co_yield n++; //与 Python 中的 yield 类似
}
- co_return
co_returnは、現在のcoroutineの実行を終了し、値を返すために使用されます
lazy<int> f() {
co_return 7;
}
もちろん、このコルティンにはいくつかの制限もあります。
- 可変長引数は使用できません
- 通常のreturnステートメントまたはプレースホルダーのreturnタイプ(autoまたはConcept)は使用できません
- constexpr関数、コンストラクター、デストラクタ、およびメイン関数をcoroutineにすることはできません
範囲
範囲ベースの要素(単純にコンテナとして理解できます)を処理するためのコンポーネントとさまざまなアダプタ、およびいくつかの新しいアルゴリズムを提供します。
主に次のカテゴリがあります。
- 範囲ベースのアクセサー
- 範囲ベースのプリミティブ
- スコープベースのコンセプト
- 見る
- 工場
- アダプタ
詳細については、ヘッダーファイルを参照してください。
簡単な例:
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> ints{
0,1,2,3,4,5};
auto even = [](int i){
return 0 == i % 2; };
auto square = [](int i) {
return i * i; };
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}
}
指定イニシャライザー(指定された初期化)
{}を使用して、配列、クラス、構造、または共用体のメンバーを初期化します。
struct A{
int a;int b;int c;};
A a{
.a=10,.b=100,.c=20};
演算子<=>
次のような3者間比較演算子:
lhs <=> rhs
その動作は次のとおりです。
(a <=> b) < 0 if lhs < rhs
(a <=> b) > 0 if lhs > rhs
(a <=> b) == 0 if lhs equal rhs
例は次のとおりです。
#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 and 0 are equal";
else if (res > 0)
std::cout << "-0 is greater than 0";
}
属性
- [[nodiscard(string-literal)]]
戻り値を無視すると警告します。 - [[可能性が高い]]および[[可能性が低い]]
は、発生する可能性が高い状況または分岐を最適化するようにコンパイラーに指示します。これは、可変値の可能性の一種の予測です。
int f(int i)
{
if (i < 0) [[unlikely]] {
return 0;
}
return 1;
}
- [[no_unique_address]]は
ストレージスペースを最適化するために使用され、メンバーが空の場合、ストレージスペースを占有しません
その他
constexprは、仮想機能のサポートを追加します。
char8_tは、utf-8文字列を格納するために使用されます。
CONSTIN
動的初期化ではなく、一定の初期化を強制する
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
labmda
値の形式でデフォルトのキャプチャパラメータをサポートしなくなりました。ディスプレイでこれを値の形式でキャプチャできるようになりました。
テンプレートをサポートし、可変パラメータをサポートします。
template <typename... Args>
void foo(Args... args) {
[...xs=args]{
bar(xs...); // xs is an init-capture pack
};
}
std :: format
{}を使用して文字列をフォーマットします。嫌なストリームをつなぎ合わせる必要はありません。以前はブースト形式を使用していましたが、これも使いやすいです。
#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello {}!\n", "world");
}
std :: span
スパンはコンテナのビューであり(つまり、コンテナは所有していません)、連続する要素のグループへの境界チェックアクセスを提供します。ビューには独自の要素がないため、構築とコピーのコストは非常に低くなります。
std :: jthread
std :: threadに似ていますが、より強力な機能を備えた新しいスレッドクラスは、停止、自動結合などをサポートします。
カレンダー和タイムゾーン
エンディアンは、列挙のサイズを決定するために使用されます
std :: make_sharedは配列をサポートします
アトミックは浮動小数点数とスマートptrをサポートします
std :: basic_syncbuf和std :: basic_osyncstream
文字列はstarts_withおよびend_with関数を追加します
std :: atomic_refアトミックリファレンス
std :: to_arrayはxxxをstd :: arrayに変換します
インライン名前空間
機能の概要
コア言語機能
ライブラリの機能
より標準的な機能の詳細については、公式のC ++リリースプラットフォームに移動することもできます。
ドラフトバージョン: