C++20 には、次の新しい言語機能が含まれています。
C++20 には、次の新しいライブラリ機能が含まれています。
C++17 には、次の新しい言語機能が含まれています。
C++17 には、次の新しいライブラリ機能が含まれています。
C++14 には、次の新しい言語機能が含まれています。
C++14 には、次の新しいライブラリ機能が含まれています。
C++11 には、次の新しい言語機能が含まれています。
C++11 には、次の新しいライブラリ機能が含まれています。
注:これらの例は基本レベルでのコルーチンの使用方法を示していますが、コードのコンパイル時にはさらに多くの処理が行われます。これらの例は、C++20 のコルーチンを完全にカバーすることを意図したものではありません。
generator
クラスとtask
クラスはまだ標準ライブラリで提供されていないため、cppcoro ライブラリを使用してこれらの例をコンパイルしました。
コルーチンは、実行を一時停止したり再開したりできる特別な関数です。コルーチンを定義するには、関数の本体にco_return
、 co_await
、またはco_yield
キーワードが存在する必要があります。 C++20 のコルーチンはスタックレスです。コンパイラによって最適化されない限り、それらの状態はヒープ上に割り当てられます。
コルーチンの例は、呼び出しごとに値を生成する (つまり、生成する)ジェネレーター関数です。
generator< int > range ( int start, int end) {
while (start < end) {
co_yield start;
start++;
}
// Implicit co_return at the end of this function:
// co_return;
}
for ( int n : range( 0 , 10 )) {
std::cout << n << std::endl;
}
上記のrange
ジェネレーター関数は、 start
からend
まで (排他的) に値を生成し、各反復ステップでstart
に格納されている現在の値を生成します。ジェネレーターは、 range
の各呼び出しにわたってその状態を維持します (この場合、呼び出しは for ループ内の反復ごとに行われます)。 co_yield
、指定された式を受け取り、その値を生成し (つまり、返し)、その時点でコルーチンを一時停止します。再開すると、 co_yield
の後に実行が続行されます。
コルーチンのもう 1 つの例は、タスクが待機しているときに実行される非同期計算であるtaskです。
task< void > echo (socket s) {
for (;;) {
auto data = co_await s. async_read ();
co_await async_write (s, data);
}
// Implicit co_return at the end of this function:
// co_return;
}
この例では、 co_await
キーワードが導入されています。このキーワードは式を受け取り、待機しているもの (この場合は読み取りまたは書き込み) の準備ができていない場合は実行を一時停止し、そうでない場合は実行を続行します。 (内部ではco_yield
co_await
使用していることに注意してください。)
タスクを使用して値を遅延評価します。
task< int > calculate_meaning_of_life () {
co_return 42 ;
}
auto meaning_of_life = calculate_meaning_of_life();
// ...
co_await meaning_of_life; // == 42
概念は、型を制約するコンパイル時述語と呼ばれます。それらは次の形式を取ります。
template < template-parameter-list >
concept concept-name = constraint-expression;
ここで、 constraint-expression
constexpr ブール値として評価されます。制約は、型が数値であるかハッシュ可能であるかなど、セマンティック要件をモデル化する必要があります。指定された型がバインドされている概念を満たさない場合 (つまり、 constraint-expression
false
返す場合)、コンパイラ エラーが発生します。制約はコンパイル時に評価されるため、より意味のあるエラー メッセージと実行時の安全性を提供できます。
// `T` is not limited by any constraints.
template < typename T>
concept always_satisfied = true ;
// Limit `T` to integrals.
template < typename T>
concept integral = std::is_integral_v<T>;
// Limit `T` to both the `integral` constraint and signedness.
template < typename T>
concept signed_integral = integral<T> && std::is_signed_v<T>;
// Limit `T` to both the `integral` constraint and the negation of the `signed_integral` constraint.
template < typename T>
concept unsigned_integral = integral<T> && !signed_integral<T>;
概念を強制するためのさまざまな構文形式があります。
// Forms for function parameters:
// `T` is a constrained type template parameter.
template <my_concept T>
void f (T v);
// `T` is a constrained type template parameter.
template < typename T>
requires my_concept<T>
void f (T v);
// `T` is a constrained type template parameter.
template < typename T>
void f (T v) requires my_concept<T>;
// `v` is a constrained deduced parameter.
void f (my_concept auto v);
// `v` is a constrained non-type template parameter.
template <my_concept auto v>
void g ();
// Forms for auto-deduced variables:
// `foo` is a constrained auto-deduced value.
my_concept auto foo = ...;
// Forms for lambdas:
// `T` is a constrained type template parameter.
auto f = []<my_concept T> (T v) {
// ...
};
// `T` is a constrained type template parameter.
auto f = []< typename T> requires my_concept<T> (T v) {
// ...
};
// `T` is a constrained type template parameter.
auto f = []< typename T> (T v) requires my_concept<T> {
// ...
};
// `v` is a constrained deduced parameter.
auto f = [](my_concept auto v) {
// ...
};
// `v` is a constrained non-type template parameter.
auto g = []<my_concept auto v> () {
// ...
};
requires
キーワードは、 requires
句またはrequires
式を開始するために使用されます。
template < typename T>
requires my_concept<T> // `requires` clause.
void f (T);
template < typename T>
concept callable = requires (T f) { f (); }; // `requires` expression.
template < typename T>
requires requires (T x) { x + x; } // `requires` clause and expression on same line.
T add (T a, T b) {
return a + b;
}
requires
式のパラメータ リストはオプションであることに注意してください。 requires
式の各要件は、次のいずれかです。
template < typename T>
concept callable = requires (T f) { f (); };
typename
キーワードとそれに続く型名で示され、指定された型名が有効であることを表明します。 struct foo {
int foo;
};
struct bar {
using value = int ;
value data;
};
struct baz {
using value = int ;
value data;
};
// Using SFINAE, enable if `T` is a `baz`.
template < typename T, typename = std:: enable_if_t <std::is_same_v<T, baz>>>
struct S {};
template < typename T>
using Ref = T&;
template < typename T>
concept C = requires {
// Requirements on type `T`:
typename T::value; // A) has an inner member named `value`
typename S<T>; // B) must have a valid class template specialization for `S`
typename Ref<T>; // C) must be a valid alias template substitution
};
template <C T>
void g (T a);
g (foo{}); // ERROR: Fails requirement A.
g (bar{}); // ERROR: Fails requirement B.
g (baz{}); // PASS.
template < typename T>
concept C = requires(T x) {
{*x} -> std::convertible_to< typename T::inner>; // the type of the expression `*x` is convertible to `T::inner`
{x + 1 } -> std::same_as< int >; // the expression `x + 1` satisfies `std::same_as<decltype((x + 1))>`
{x * 1 } -> std::convertible_to<T>; // the type of the expression `x * 1` is convertible to `T`
};
requires
キーワードで示され、追加の制約 (ローカル パラメーター引数に対する制約など) を指定します。 template < typename T>
concept C = requires(T x) {
requires std::same_as< sizeof (x), size_t >;
};
概念ライブラリも参照してください。
C++20 では、ボイラープレートを減らし、開発者がより明確な比較セマンティクスを定義できるようにする比較関数を記述する新しい方法として、宇宙船演算子 ( <=>
) を導入しています。 3 方向比較演算子を定義すると、他の比較演算子関数 (つまり==
、 !=
、 <
など) が自動生成されます。
3 つの順序が導入されています。
std::strong_ordering
: 強い順序付けでは、等しい (同一および交換可能) 項目が区別されます。 less
」、 greater
」、 equivalent
」、 equal
順序付けを提供します。比較の例: リスト内の特定の値、整数値、大文字と小文字を区別する文字列の検索。std::weak_ordering
: 弱い順序付けでは、同等の項目 (同一ではありませんが、比較の目的で交換可能) が区別されます。 less
、 greater
、およびequivalent
順序付けを提供します。比較の例: 大文字と小文字を区別しない文字列、並べ替え、クラスの表示可能なメンバーのすべてではなく一部の比較。std::partial_ordering
: 部分順序付けは弱い順序付けと同じ原則に従いますが、順序付けが不可能な場合も含まれます。 less
、 greater
、 equivalent
、およびunordered
順序付けを提供します。比較の例: 浮動小数点値 (例: NaN
)。デフォルトの 3 方向比較演算子は、メンバーごとの比較を行います。
struct foo {
int a;
bool b;
char c;
// Compare `a` first, then `b`, then `c` ...
auto operator <=>( const foo&) const = default ;
};
foo f1{ 0 , false , ' a ' }, f2{ 0 , true , ' b ' };
f1 < f2; // == true
f1 == f2; // == false
f1 >= f2; // == false
独自の比較を定義することもできます。
struct foo {
int x;
bool b;
char c;
std::strong_ordering operator <=>( const foo& other) const {
return x <=> other. x ;
}
};
foo f1{ 0 , false , ' a ' }, f2{ 0 , true , ' b ' };
f1 < f2; // == false
f1 == f2; // == true
f1 >= f2; // == true
C スタイルの指定された初期化子構文。指定された初期化子リストに明示的にリストされていないメンバー フィールドは、デフォルトで初期化されます。
struct A {
int x;
int y;
int z = 123 ;
};
A a {. x = 1 , . z = 2 }; // a.x == 1, a.y == 0, a.z == 2
ラムダ式では使い慣れたテンプレート構文を使用します。
auto f = []< typename T>(std::vector<T> v) {
// ...
};
この機能は、一般的なコード パターンを簡素化し、スコープを厳密に保つのに役立ち、一般的なライフタイム問題に対する洗練されたソリューションを提供します。
for ( auto v = std::vector{ 1 , 2 , 3 }; auto & e : v) {
std::cout << e;
}
// prints "123"
ラベル付きステートメントが実行される可能性が高いというヒントをオプティマイザーに提供します。
switch (n) {
case 1 :
// ...
break ;
[[likely]] case 2 : // n == 2 is considered to be arbitrarily more
// ... // likely than any other value of n
break ;
}
if ステートメントの右括弧の後に「可能性が高い」/「可能性が低い」属性の 1 つが表示される場合、そのブランチでサブステートメント (本体) が実行される可能性が高いか、可能性が低いことを示します。
int random = get_random_number_between_x_and_y( 0 , 3 );
if (random > 0 ) [[likely]] {
// body of if statement
// ...
}
反復ステートメントのサブステートメント (本体) にも適用できます。
while (unlikely_truthy_condition) [[unlikely]] {
// body of while statement
// ...
}
[=]
使用してラムダ キャプチャでthis
暗黙的にキャプチャすることは非推奨になりました。 [=, this]
または[=, *this]
を使用して明示的にキャプチャすることを好みます。
struct int_value {
int n = 0 ;
auto getter_fn () {
// BAD:
// return [=]() { return n; };
// GOOD:
return [=, * this ]() { return n; };
}
};
クラスを型以外のテンプレート パラメーターで使用できるようになりました。テンプレート引数として渡されるオブジェクトの型はconst T
です。ここで、 T
オブジェクトの型であり、静的な保存期間を持ちます。
struct foo {
foo () = default ;
constexpr foo ( int ) {}
};
template <foo f = {}>
auto get_foo () {
return f;
}
get_foo (); // uses implicit constructor
get_foo<foo{ 123 }>();
仮想関数をconstexpr
してコンパイル時に評価できるようになりました。 constexpr
仮想関数は非constexpr
仮想関数をオーバーライドでき、またその逆も可能です。
struct X1 {
virtual int f () const = 0;
};
struct X2 : public X1 {
constexpr virtual int f () const { return 2 ; }
};
struct X3 : public X2 {
virtual int f () const { return 3 ; }
};
struct X4 : public X3 {
constexpr virtual int f () const { return 4 ; }
};
constexpr X4 x4;
x4.f(); // == 4
コンストラクターを明示的にするかどうかをコンパイル時に条件付きで選択します。 explicit(true)
explicit
に指定するのと同じです。
struct foo {
// Specify non-integral types (strings, floats, etc.) require explicit construction.
template < typename T>
explicit (!std::is_integral_v<T>) foo(T) {}
};
foo a = 123 ; // OK
foo b = " 123 " ; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)
foo c { " 123 " }; // OK
constexpr
関数と似ていますが、 consteval
指定子を持つ関数は定数を生成する必要があります。これらはimmediate functions
と呼ばれます。
consteval int sqr ( int n) {
return n * n;
}
constexpr int r = sqr( 100 ); // OK
int x = 100 ;
int r2 = sqr(x); // ERROR: the value of 'x' is not usable in a constant expression
// OK if `sqr` were a `constexpr` function
可読性を向上させるために、列挙型のメンバーをスコープに取り込みます。前に:
enum class rgba_color_channel { red, green, blue, alpha };
std::string_view to_string (rgba_color_channel channel) {
switch (channel) {
case rgba_color_channel::red: return " red " ;
case rgba_color_channel::green: return " green " ;
case rgba_color_channel::blue: return " blue " ;
case rgba_color_channel::alpha: return " alpha " ;
}
}
後:
enum class rgba_color_channel { red, green, blue, alpha };
std::string_view to_string (rgba_color_channel my_channel) {
switch (my_channel) {
using enum rgba_color_channel;
case red: return " red " ;
case green: return " green " ;
case blue: return " blue " ;
case alpha: return " alpha " ;
}
}
パラメータ パックを値でキャプチャします。
template < typename ... Args>
auto f (Args&&... args){
// BY VALUE:
return [... args = std::forward<Args>(args)] {
// ...
};
}
パラメータ パックを参照によってキャプチャします。
template < typename ... Args>
auto f (Args&&... args){
// BY REFERENCE:
return [&... args = std::forward<Args>(args)] {
// ...
};
}
UTF-8 文字列を表すための標準タイプを提供します。
char8_t utf8_str[] = u8" u0123 " ;
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 = g( false ); // ERROR: `g` is not constexpr, so `d` cannot be evaluated at compile-time.
可変個引数マクロが空でない場合に、指定された引数を評価することにより、可変個引数マクロのサポートを支援します。
# define F (...) f( 0 __VA_OPT__ (,) __VA_ARGS__)
F(a, b, c) // replaced by f(0, a, b, c)
F() // replaced by f(0)
より複雑な概念を構築するための概念は、標準ライブラリによっても提供されます。これらには次のようなものがあります。
中心となる言語の概念:
same_as
- 2 つのタイプが同じであることを指定します。derived_from
- 型が別の型から派生することを指定します。convertible_to
- 型が別の型に暗黙的に変換可能であることを指定します。common_with
- 2 つの型が共通の型を共有することを指定します。integral
- 型が整数型であることを指定します。default_constructible
- ある型のオブジェクトをデフォルトで構築できることを指定します。比較の概念:
boolean
- 型がブール値コンテキストで使用できることを指定します。equality_comparable
- operator==
が等価関係であることを指定します。オブジェクトの概念:
movable
- あるタイプのオブジェクトが移動および交換できることを指定します。copyable
- あるタイプのオブジェクトがコピー、移動、および交換できることを指定します。semiregular
- ある型のオブジェクトをコピー、移動、交換、およびデフォルトで構築できることを指定します。regular
- 型がRegularであること、つまり、 semiregular
であり、 equality_comparable
あることを指定します。呼び出し可能な概念:
invocable
- 指定された引数型のセットを使用して呼び出し可能な型を呼び出すことができることを指定します。predicate
- 呼び出し可能な型がブール述語であることを指定します。概念も参照してください。
printf
の単純さとiostream
のタイプセーフを組み合わせます。中括弧をプレースホルダーとして使用し、printf スタイルの指定子と同様のカスタム書式設定をサポートします。
std::format ( " {1} {0} " , " world " , " hello " ); // == "hello world"
int x = 123 ;
std::string str = std::format( " x: {} " , x); // str == "x: 123"
// Format to an output iterator:
for ( auto x : { 1 , 2 , 3 }) {
std::format_to (std::ostream_iterator< char >{std::cout, " n " }, " {} " , x);
}
カスタムタイプをフォーマットするには:
struct fraction {
int numerator;
int denominator;
};
template <>
struct std ::formatter<fraction>
{
constexpr auto parse (std::format_parse_context& ctx) {
return ctx. begin ();
}
auto format ( const fraction& f, std::format_context& ctx) const {
return std::format_to (ctx. out (), " {0:d}/{1:d} " , f. numerator , f. denominator );
}
};
fraction f{ 1 , 2 };
std::format ( " {} " , f); // == "1/2"
ラップされた出力ストリームの出力操作をバッファリングして同期を確保します (つまり、出力のインターリーブがありません)。
std::osyncstream{std::cout} << " The value of x is: " << x << std::endl;
スパンは、要素の連続グループへの境界チェックされたアクセスを提供するコンテナのビュー (つまり、非所有) です。ビューは要素を所有していないため、構築やコピーが安価です。ビューについて簡単に考えると、ビューはデータへの参照を保持していることになります。ポインタ/イテレータと長さフィールドを維持するのとは対照的に、スパンはそれらの両方を 1 つのオブジェクトにラップします。
スパンは、動的にサイズを変更することも、固定サイズ(エクステントと呼ばれる)に変更することもできます。固定サイズのスパンは境界チェックの恩恵を受けます。
Span は const を伝播しないため、読み取り専用の Span を構築するにはstd::span<const T>
を使用します。
例: 動的にサイズ変更されるスパンを使用して、さまざまなコンテナーから整数を出力します。
void print_ints (std::span< const int > ints) {
for ( const auto n : ints) {
std::cout << n << std::endl;
}
}
print_ints (std::vector{ 1 , 2 , 3 });
print_ints (std::array< int , 5 >{ 1 , 2 , 3 , 4 , 5 });
int a[ 10 ] = { 0 };
print_ints (a);
// etc.
例: 静的にサイズ設定されたスパンは、スパンの範囲と一致しないコンテナーのコンパイルに失敗します。
void print_three_ints (std::span< const int , 3 > ints) {
for ( const auto n : ints) {
std::cout << n << std::endl;
}
}
print_three_ints (std::vector{ 1 , 2 , 3 }); // ERROR
print_three_ints (std::array< int , 5 >{ 1 , 2 , 3 , 4 , 5 }); // ERROR
int a[ 10 ] = { 0 };
print_three_ints (a); // ERROR
std::array< int , 3 > b = { 1 , 2 , 3 };
print_three_ints (b); // OK
// You can construct a span manually if required:
std::vector c{ 1 , 2 , 3 };
print_three_ints (std::span< const int , 3 >{ c. data (), 3 }); // OK: set pointer and length field.
print_three_ints (std::span< const int , 3 >{ c. cbegin (), c. cend () }); // OK: use iterator pairs.
C++20 は、popcount を含むいくつかのビット操作を提供する新しい<bit>
ヘッダーを提供します。
std::popcount ( 0u ); // 0
std::popcount ( 1u ); // 1
std::popcount ( 0b1111'0000u ); // 4
<numbers>
ヘッダーで定義される PI、オイラー数などの数学定数。
std::numbers:: pi ; // 3.14159...
std::numbers::e; // 2.71828...
コンパイル時のコンテキストで呼び出された場合に真となる述語関数。
constexpr bool is_compile_time () {
return std::is_constant_evaluated ();
}
constexpr bool a = is_compile_time(); // true
bool b = is_compile_time(); // false
auto p = std::make_shared< int []>( 5 ); // pointer to `int[5]`
// OR
auto p = std::make_shared< int [ 5 ]>(); // pointer to `int[5]`
文字列 (および文字列ビュー) には、文字列が指定された文字列で始まるか終了するかをチェックするためのstarts_with
およびends_with
メンバー関数が追加されました。
std::string str = " foobar " ;
str.starts_with( " foo " ); // true
str.ends_with( " baz " ); // false
セットやマップなどの連想コンテナーには、 contains
メンバー関数があり、「イテレーターの終わりを検索して確認する」というイディオムの代わりに使用できます。
std::map< int , char > map {{ 1 , ' a ' }, { 2 , ' b ' }};
map.contains( 2 ); // true
map.contains( 123 ); // false
std::set< int > set { 1 , 2 , 3 };
set.contains( 2 ); // true
オブジェクトをある型から別の型に再解釈するためのより安全な方法。
float f = 123.0 ;
int i = std::bit_cast< int >(f);
2 つの整数の中点を安全に (オーバーフローせずに) 計算します。
std::midpoint ( 1 , 3 ); // == 2
指定された配列/「配列のような」オブジェクトをstd::array
に変換します。
std::to_array ( " foo " ); // returns `std::array<char, 4>`
std::to_array< int >({ 1 , 2 , 3 }); // returns `std::array<int, 3>`
int a[] = { 1 , 2 , 3 };
std::to_array (a); // returns `std::array<int, 3>`
最初の N 個の引数 (N は、指定された関数からstd::bind_front
への後の引数の数) を指定された自由関数、ラムダ関数、またはメンバー関数にバインドします。
const auto f = []( int a, int b, int c) { return a + b + c; };
const auto g = std::bind_front(f, 1 , 1 );
g ( 1 ); // == 3
文字列、リスト、ベクター、マップなどのさまざまな STL コンテナーにstd::erase
および/またはstd::erase_if
提供します。
値による消去にはstd::erase
使用し、要素を消去する場合の述語を指定するにはstd::erase_if
を使用します。どちらの関数も、消去された要素の数を返します。
std::vector v{ 0 , 1 , 0 , 2 , 0 , 3 };
std::erase (v, 0 ); // v == {1, 2, 3}
std::erase_if (v, []( int n) { return n == 0 ; }); // v == {1, 2, 3}
比較結果に名前を付けるためのヘルパー関数:
std::is_eq ( 0 <=> 0 ); // == true
std::is_lteq ( 0 <=> 1 ); // == true
std::is_gt ( 0 <=> 1 ); // == false
3 者間比較も参照してください。
3 方向比較を使用して 2 つの範囲を辞書順に比較し、適用可能な最も強力な比較カテゴリ タイプの結果を生成します。
std::vector a{ 0 , 0 , 0 }, b{ 0 , 0 , 0 }, c{ 1 , 1 , 1 };
auto cmp_ab = std::lexicographical_compare_three_way(
a.begin(), a.end(), b.begin(), b.end());
std::is_eq (cmp_ab); // == true
auto cmp_ac = std::lexicographical_compare_three_way(
a.begin(), a.end(), c.begin(), c.end());
std::is_lt (cmp_ac); // == true
「3 者間比較」、「3 者間比較ヘルパー」も参照してください。
テンプレート引数の自動推論は関数の場合とよく似ていますが、クラス コンストラクターが含まれるようになりました。
template < typename T = float >
struct MyContainer {
T val;
MyContainer () : val{} {}
MyContainer (T val) : val{val} {}
// ...
};
MyContainer c1 { 1 }; // OK MyContainer<int>
MyContainer c2; // OK MyContainer<float>
auto
の推論ルールに従って、許容される型の非型テンプレート パラメーター リストを尊重しながら[*]、テンプレート引数はその引数の型から推論できます。
template < auto ... seq>
struct my_integer_sequence {
// Implementation here ...
};
// Explicitly pass type `int` as template argument.
auto seq = std::integer_sequence< int , 0 , 1 , 2 >();
// Type is deduced to be `int`.
auto seq2 = my_integer_sequence< 0 , 1 , 2 >();
* - たとえば、テンプレート パラメーター タイプとしてdouble
使用することはできません。これも、 auto
使用した無効な推論になります。
フォールド式は、二項演算子に対してテンプレート パラメーター パックのフォールドを実行します。
(... op e)
または(e op ...)
の形式の式 ( op
はフォールド演算子、 e
は展開されていないパラメーター パック) は、単項フォールドと呼ばれます。(e1 op ... op e2)
形式の式 ( op
はフォールド演算子) は、バイナリフォールドと呼ばれます。 e1
またはe2
のいずれかは未展開のパラメータ パックですが、両方ではありません。 template < typename ... Args>
bool logicalAnd (Args... args) {
// Binary folding.
return ( true && ... && args);
}
bool b = true ;
bool & b2 = b;
logicalAnd (b, b2, true ); // == true
template < typename ... Args>
auto sum (Args... args) {
// Unary folding.
return (... + args);
}
sum ( 1.0 , 2 . 0f , 3 ); // == 6.0
統一初期化構文で使用した場合のauto
控除に変更されます。以前は、 auto x {3};
std::initializer_list<int>
を推定しますが、これはint
に推定されます。
auto x1 { 1 , 2 , 3 }; // error: not a single element
auto x2 = { 1 , 2 , 3 }; // x2 is std::initializer_list<int>
auto x3 { 3 }; // x3 is int
auto x4 { 3.0 }; // x4 is double
constexpr
を使用したコンパイル時のラムダ。
auto identity = []( int n) constexpr { return n; };
static_assert (identity( 123 ) == 123);
constexpr auto add = []( int x, int y) {
auto L = [=] { return x; };
auto R = [=] { return y; };
return [=] { return L () + R (); };
};
static_assert (add( 1 , 2 )() == 3);
constexpr int addOne ( int n) {
return [n] { return n + 1 ; }();
}
static_assert (addOne( 1 ) == 2);
this
値でキャプチャしますラムダ環境でthis
キャプチャすることは、以前は参照のみでした。これが問題となる例としては、オブジェクトが有効期間を過ぎても使用可能である必要があるコールバックを使用する非同期コードが挙げられます。 *this
(C++17) は現在のオブジェクトのコピーを作成しますが、 this
(C++11) は参照によるキャプチャを継続します。
struct MyObj {
int value { 123 };
auto getValueCopy () {
return [* this ] { return value; };
}
auto getValueRef () {
return [ this ] { return value; };
}
};
MyObj mo;
auto valueCopy = mo.getValueCopy();
auto valueRef = mo.getValueRef();
mo.value = 321 ;
valueCopy (); // 123
valueRef (); // 321
インライン指定子は関数だけでなく変数にも適用できます。インラインで宣言された変数は、インラインで宣言された関数と同じセマンティクスを持ちます。
// Disassembly example using compiler explorer.
struct S { int x; };
inline S x1 = S{ 321 }; // mov esi, dword ptr [x1]
// x1: .long 321
S x2 = S{ 123 }; // mov eax, dword ptr [.L_ZZ4mainE2x2]
// mov dword ptr [rbp - 8], eax
// .L_ZZ4mainE2x2: .long 123
また、ソース ファイル内で初期化する必要がないように、静的メンバー変数を宣言および定義するために使用することもできます。
struct S {
S () : id{count++} {}
~S () { count--; }
int id;
static inline int count{ 0 }; // declare and initialize count to 0 within the class
};
名前空間解決演算子を使用して、ネストされた名前空間定義を作成します。
namespace A {
namespace B {
namespace C {
int i;
}
}
}
上記のコードは次のように記述できます。
namespace A ::B::C {
int i;
}
auto [ x, y, z ] = expr;
と書くことを可能にする、初期化の構造を解除するための提案。ここで、 expr
の型はタプルのようなオブジェクトで、その要素は変数x
、 y
、およびz
(この構造体が宣言する) にバインドされます。タプルのようなオブジェクトには、 std::tuple
、 std::pair
、 std::array
、および集約構造が含まれます。
using Coordinate = std::pair< int , int >;
Coordinate origin () {
return Coordinate{ 0 , 0 };
}
const auto [ x, y ] = origin();
x; // == 0
y; // == 0
std::unordered_map<std::string, int > mapping {
{ " a " , 1 },
{ " b " , 2 },
{ " c " , 3 }
};
// Destructure by reference.
for ( const auto & [key, value] : mapping) {
// Do something with key and value
}
if
ステートメントとswitch
ステートメントの新しいバージョンは、一般的なコード パターンを簡素化し、ユーザーがスコープを厳密に保つのに役立ちます。
{
std::lock_guard<std::mutex> lk (mx);
if (v. empty ()) v. push_back (val);
}
// vs.
if (std::lock_guard<std::mutex> lk (mx); v.empty()) {
v. push_back (val);
}
Foo gadget (args);
switch ( auto s = gadget.status()) {
case OK: gadget. zip (); break ;
case Bad: throw BadFoo (s. message ());
}
// vs.
switch (Foo gadget (args); auto s = gadget.status()) {
case OK: gadget. zip (); break ;
case Bad: throw BadFoo (s. message ());
}
コンパイル時の条件に応じてインスタンス化されるコードを作成します。
template < typename T>
constexpr bool isIntegral () {
if constexpr (std::is_integral<T>::value) {
return true ;
} else {
return false ;
}
}
static_assert (isIntegral< int >() == true);
static_assert (isIntegral< char >() == true);
static_assert (isIntegral< double >() == false);
struct S {};
static_assert (isIntegral<S>() == false);
u8
で始まる文字リテラルは、 char
型の文字リテラルです。 UTF-8 文字リテラルの値は、ISO 10646 コード ポイント値と同じです。
char x = u8 ' x ' ;
中括弧構文を使用して列挙型を初期化できるようになりました。
enum byte : unsigned char {};
byte b { 0 }; // OK
byte c {- 1 }; // ERROR
byte d = byte{ 1 }; // OK
byte e = byte{ 256 }; // ERROR
C++17 では、 [[fallthrough]]
、 [[nodiscard]]
、および[[maybe_unused]]
という 3 つの新しい属性が導入されています。
[[fallthrough]]
switch ステートメントでのフォールスルーが意図された動作であることをコンパイラーに示します。この属性は switch ステートメント内でのみ使用でき、次の case/default ラベルの前に配置する必要があります。 switch (n) {
case 1 :
// ...
[[fallthrough]];
case 2 :
// ...
break ;
case 3 :
// ...
[[fallthrough]];
default :
// ...
}
[[nodiscard]]
関数またはクラスのいずれかにこの属性があり、その戻り値が破棄された場合に警告を発行します。 [[nodiscard]] bool do_something () {
return is_success; // true for success, false for failure
}
do_something (); // warning: ignoring return value of 'bool do_something()',
// declared with attribute 'nodiscard'
// Only issues a warning when `error_info` is returned by value.
struct [[nodiscard]] error_info {
// ...
};
error_info do_something () {
error_info ei;
// ...
return ei;
}
do_something (); // warning: ignoring returned value of type 'error_info',
// declared with attribute 'nodiscard'
[[maybe_unused]]
変数またはパラメーターが未使用である可能性があり、意図されているものであることをコンパイラーに示します。 void my_callback (std::string msg, [[maybe_unused]] bool error) {
// Don't care if `msg` is an error message, just log it.
log (msg);
}
__has_include (operand)
演算子を#if
および#elif
式で使用して、ヘッダーまたはソース ファイル ( operand
) をインクルードできるかどうかを確認できます。
この使用例の 1 つは、同じように動作する 2 つのライブラリを使用し、優先するライブラリがシステム上に見つからない場合はバックアップ/実験用ライブラリを使用することです。
# ifdef __has_include
# if __has_include(<optional>)
# include < optional >
# define have_optional 1
# elif __has_include(<experimental/optional>)
# include < experimental/optional >
# define have_optional 1
# define experimental_optional
# else
# define have_optional 0
# endif
# endif
また、プログラムがどのプラットフォームで実行されているかを知らなくても、さまざまなプラットフォーム上の異なる名前や場所に存在するヘッダーを含めるのにも使用できます。OpenGL ヘッダーはその良い例であり、macOS ではOpenGL
ディレクトリに、他のプラットフォームではGL
にあります。プラットフォーム。
# ifdef __has_include
# if __has_include(<OpenGL/gl.h>)
# include < OpenGL/gl.h >
# include < OpenGL/glu.h >
# elif __has_include(<GL/gl.h>)
# include < GL/gl.h >
# include < GL/glu.h >
# else
# error No suitable OpenGL headers found.
# endif
# endif
クラス テンプレート引数推論(CTAD) を使用すると、コンパイラはコンストラクター引数からテンプレート引数を推論できます。
std::vector v{ 1 , 2 , 3 }; // deduces std::vector<int>
std::mutex mtx;
auto lck = std::lock_guard{ mtx }; // deduces to std::lock_guard<std::mutex>
auto p = new std::pair{ 1.0 , 2.0 }; // deduces to std::pair<double, double>*
ユーザー定義型の場合、推論ガイドを使用して、該当する場合にテンプレート引数を推論する方法をコンパイラーにガイドできます。
template < typename T>
struct container {
container (T t) {}
template < typename Iter>
container (Iter beg, Iter end);
};
// deduction guide
template < typename Iter>
container (Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
container a{ 7 }; // OK: deduces container<int>
std::vector< double > v{ 1.0 , 2.0 , 3.0 };
auto b = container{ v. begin (), v. end () }; // OK: deduces container<double>
container c{ 5 , 6 }; // ERROR: std::iterator_traits<int>::value_type is not a type
クラス テンプレートstd::variant
タイプ セーフなunion
表します。 std::variant
のインスタンスは常に、その代替型のいずれかの値を保持します (値が存在しないことも可能です)。
std::variant< int , double > v{ 12 };
std::get< int >(v); // == 12
std::get< 0 >(v); // == 12
v = 12.0 ;
std::get< double >(v); // == 12.0
std::get< 1 >(v); // == 12.0
クラス テンプレートstd::optional
オプションの含まれる値、つまり、存在する場合も存在しない場合もある値を管理します。オプションの一般的な使用例は、失敗する可能性のある関数の戻り値です。
std::optional<std::string> create ( bool b) {
if (b) {
return " Godzilla " ;
} else {
return {};
}
}
create ( false ).value_or( " empty " ); // == "empty"
create ( true ).value(); // == "Godzilla"
// optional-returning factory functions are usable as conditions of while and if
if ( auto str = create( true )) {
// ...
}
任意の型の単一値を格納できる型安全なコンテナー。
std::any x { 5 };
x.has_value() // == true
std::any_cast< int >(x) // == 5
std::any_cast< int &>(x) = 10 ;
std::any_cast< int >(x) // == 10
文字列への非所有参照。文字列の上に抽象化を提供する場合に便利です (解析など)。
// Regular strings.
std::string_view cppstr { " foo " };
// Wide strings.
std::wstring_view wcstr_v { L" baz " };
// Character arrays.
char array[ 3 ] = { ' b ' , ' a ' , ' r ' };
std::string_view array_v (array, std::size(array));
std::string str { " trim me " };
std::string_view v {str};
v.remove_prefix(std::min(v.find_first_not_of( " " ), v.size()));
str; // == " trim me"
v; // == "trim me"
パラメーターを使用してCallable
オブジェクトを呼び出します。呼び出し可能なオブジェクトの例はstd::function
または lambda です。通常の関数と同様に呼び出すことができるオブジェクト。
template < typename Callable>
class Proxy {
Callable c_;
public:
Proxy (Callable c) : c_{ std::move (c) } {}
template < typename ... Args>
decltype ( auto ) operator ()(Args&&... args) {
// ...
return std::invoke (c_, std::forward<Args>(args)...);
}
};
const auto add = []( int x, int y) { return x + y; };
Proxy p{ add };
p ( 1 , 2 ); // == 3
引数のタプルを使用してCallable
オブジェクトを呼び出します。
auto add = []( int x, int y) {
return x + y;
};
std::apply (add, std::make_tuple( 1 , 2 )); // == 3
新しいstd::filesystem
ライブラリは、ファイル システム内のファイル、ディレクトリ、パスを操作する標準的な方法を提供します。
ここでは、使用可能なスペースがある場合、大きなファイルが一時パスにコピーされます。
const auto bigFilePath { " bigFileToCopy " };
if (std::filesystem::exists(bigFilePath)) {
const auto bigFileSize { std::filesystem::file_size (bigFilePath)};
std::filesystem::path tmpPath { " /tmp " };
if ( std::filesystem::space (tmpPath). available > bigFileSize) {
std::filesystem::create_directory (tmpPath. append ( " example " ));
std::filesystem::copy_file (bigFilePath, tmpPath. append ( " newFile " ));
}
}
新しいstd::byte
型は、データをバイトとして表す標準的な方法を提供します。 char
またはunsigned char
ではなくstd::byte
を使用する利点は、std::byte が文字型ではなく、算術型でもないことです。一方、利用可能な演算子のオーバーロードはビット単位の演算のみです。
std::byte a { 0 };
std::byte b { 0xFF };
int i = std::to_integer< int >(b); // 0xFF
std::byte c = a & b;
int j = std::to_integer< int >(c); // 0
std::byte
単なる列挙型であり、列挙型の直接リスト初期化のおかげで、列挙型の中括弧付き初期化が可能になることに注意してください。
コストのかかるコピー、移動、ヒープの割り当て/割り当て解除などのオーバーヘッドを発生させずに、ノードを移動したりコンテナをマージしたりできます。
要素をあるマップから別のマップに移動するには:
std::map< int , string> src {{ 1 , " one " }, { 2 , " two " }, { 3 , " buckle my shoe " }};
std::map< int , string> dst {{ 3 , " three " }};
dst.insert(src.extract(src.find( 1 ))); // Cheap remove and insert of { 1, "one" } from `src` to `dst`.
dst.insert(src.extract( 2 )); // Cheap remove and insert of { 2, "two" } from `src` to `dst`.
// dst == { { 1, "one" }, { 2, "two" }, { 3, "three" } };
セット全体を挿入する:
std::set< int > src { 1 , 3 , 5 };
std::set< int > dst { 2 , 4 , 5 };
dst.merge(src);
// src == { 5 }
// dst == { 1, 2, 3, 4, 5 }
コンテナよりも存続する要素を挿入する:
auto elementFactory () {
std::set<...> s;
s. emplace (...);
return s. extract (s. begin ());
}
s2.insert(elementFactory());
マップ要素のキーを変更する:
std::map< int , string> m {{ 1 , " one " }, { 2 , " two " }, { 3 , " three " }};
auto e = m.extract( 2 );
e.key() = 4 ;
m.insert(std::move(e));
// m == { { 1, "one" }, { 3, "three" }, { 4, "two" } }
copy
、 find
、 sort
メソッドなどの STL アルゴリズムの多くは、並列実行ポリシーであるseq
、 par
、およびpar_unseq
のサポートを開始しました。これらは、「順次」、「並列」、および「順序付けされていない並列」に変換されます。
std::vector< int > longVector;
// Find element using parallel execution policy
auto result1 = std::find(std::execution::par, std::begin(longVector), std::end(longVector), 2 );
// Sort elements using sequential execution policy
auto result2 = std::sort(std::execution::seq, std::begin(longVector), std::end(longVector));
すべての要素が同じ確率で選択される、指定されたシーケンス内の n 要素を (置換なしで) サンプリングします。
const std::string ALLOWED_CHARS = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 " ;
std::string guid;
// Sample 5 characters from ALLOWED_CHARS.
std::sample (ALLOWED_CHARS.begin(), ALLOWED_CHARS.end(), std::back_inserter(guid),
5, std::mt19937{ std::random_device{}() });
std::cout << guid; // e.g. G1fW2
指定された値を下限と上限の間にクランプします。
std::clamp ( 42 , - 1 , 1 ); // == 1
std::clamp (- 42 , - 1 , 1 ); // == -1
std::clamp ( 0 , - 1 , 1 ); // == 0
// `std::clamp` also accepts a custom comparator:
std::clamp ( 0 , - 1 , 1 , std::less<>{}); // == 0
指定された範囲の要素を折り畳みます。概念的にはstd::accumulate
に似ていますが、 std::reduce
フォールドを並行して実行します。フォールドは並列で実行されるため、二項演算を指定する場合は結合的かつ可換である必要があります。また、特定のバイナリ演算では、特定の範囲内の要素を変更したり、反復子を無効にしたりしてはなりません。
デフォルトのバイナリ演算は std::plus で、初期値は 0 です。
const std::array< int , 3 > a{ 1 , 2 , 3 };
std::reduce (std::cbegin(a), std::cend(a)); // == 6
// Using a custom binary op:
std::reduce (std::cbegin(a), std::cend(a), 1, std::multiplies<>{}); // == 6
さらに、リデューサーの変換を指定できます。
std::transform_reduce (std::cbegin(a), std::cend(a), 0, std::plus<>{}, times_ten); // == 60
const std::array< int , 3 > b{ 1 , 2 , 3 };
const auto product_times_ten = []( const auto a, const auto b) { return a * b * 10 ; };
std::transform_reduce (std::cbegin(a), std::cend(a), std::cbegin(b), 0, std::plus<>{}, product_times_ten); // == 140
変換とともにプレフィックス合計 (包含スキャンと排他スキャンの両方) をサポートします。
const std::array< int , 3 > a{ 1 , 2 , 3 };
std::inclusive_scan (std::cbegin(a), std::cend(a),
std::ostream_iterator<int>{ std::cout, " " }, std::plus<>{}); // 1 3 6
std::exclusive_scan (std::cbegin(a), std::cend(a),
std::ostream_iterator<int>{ std::cout, " " }, 0 , std::plus<>{}); // 0 1 3
const auto times_ten = []( const auto n) { return n * 10 ; };
std::transform_inclusive_scan (std::cbegin(a), std::cend(a),
std::ostream_iterator<int>{ std::cout, " " }, std::plus<>{}, times_ten); // 10 30 60
std::transform_exclusive_scan (std::cbegin(a), std::cend(a),
std::ostream_iterator<int>{ std::cout, " " }, 0 , std::plus<>{}, times_ten); // 0 10 30
最大公約数 (GCD) と最小公倍数 (LCM)。
const int p = 9 ;
const int q = 3 ;
std::gcd (p, q); // == 3
std::lcm (p, q); // == 9
指定された関数の結果の否定を返すユーティリティ関数。
const std::ostream_iterator< int > ostream_it{ std::cout, " " };
const auto is_even = []( const auto n) { return n % 2 == 0 ; };
std::vector< int > v{ 0 , 1 , 2 , 3 , 4 };
// Print all even numbers.
std::copy_if (std::cbegin(v), std::cend(v), ostream_it, is_even); // 0 2 4
// Print all odd (not even) numbers.
std::copy_if (std::cbegin(v), std::cend(v), ostream_it, std::not_fn(is_even)); // 1 3
整数と浮動小数点数を文字列に、またはその逆に変換します。変換はスローせず、割り当ても行わないため、C 標準ライブラリの同等の変換よりも安全です。
ユーザーは、 std::to_chars
に必要な十分なストレージを割り当てる責任があります。割り当てないと、戻り値にエラー コード オブジェクトが設定され、関数が失敗します。
これらの関数を使用すると、オプションで基数 (デフォルトは基数 10) または浮動小数点型入力の書式指定子を渡すことができます。
std::to_chars
関数が指定されたバッファ内に書き込んだ文字列の末尾の 1 つ後ろにある (非 const) char ポインタとエラー コード オブジェクトを返します。std::from_chars
成功すると関数に渡された終了ポインタと等しい const char ポインタとエラー コード オブジェクトを返します。これらの関数から返されるエラー コード オブジェクトは両方とも、成功した場合のデフォルトで初期化されたエラー コード オブジェクトと同じです。
数値123
std::string
に変換します。
const int n = 123 ;
// Can use any container, string, array, etc.
std::string str;
str.resize( 3 ); // hold enough storage for each digit of `n`
const auto [ ptr, ec ] = std::to_chars(str.data(), str.data() + str.size(), n);
if (ec == std::errc{}) { std::cout << str << std::endl; } // 123
else { /* handle failure */ }
値"123"
のstd::string
を整数に変換します。
const std::string str{ " 123 " };
int n;
const auto [ ptr, ec ] = std::from_chars(str.data(), str.data() + str.size(), n);
if (ec == std::errc{}) { std::cout << n << std::endl; } // 123
else { /* handle failure */ }
std::chrono::duration
およびstd::chrono::time_point
に abs、round、ceil、floor ヘルパー関数を提供します。
using seconds = std::chrono::seconds;
std::chrono::milliseconds d{ 5500 };
std::chrono::abs (d); // == 5s
std::chrono::round<seconds>(d); // == 6s
std::chrono::ceil<seconds>(d); // == 6s
std::chrono::floor<seconds>(d); // == 5s
バイナリ リテラルは、基数 2 の数値を表す便利な方法を提供します。 '
を使用して数字を区切ることができます。
0b110 // == 6
0b1111'1111 // == 255
C++14 では、パラメーター リストでauto
型指定子を使用できるようになり、多態性ラムダが有効になります。
auto identity = []( auto x) { return x; };
int three = identity( 3 ); // == 3
std::string foo = identity( " foo " ); // == "foo"
これにより、任意の式で初期化されたラムダ キャプチャを作成できます。キャプチャされた値に付けられた名前は、それを囲んでいるスコープ内の変数に関連している必要はなく、ラムダ本体内に新しい名前が導入されます。初期化式は、ラムダが呼び出されたときではなく、作成されたときに評価されます。
int factory ( int i) { return i * 10 ; }
auto f = [x = factory( 2 )] { return x; }; // returns 20
auto generator = [x = 0 ] () mutable {
// this would not compile without 'mutable' as we are modifying x on each call
return x++;
};
auto a = generator(); // == 0
auto b = generator(); // == 1
auto c = generator(); // == 2
以前はコピーまたは参照によってしかキャプチャできなかった値をラムダに移動(または転送) できるようになったので、ラムダ内の移動のみの型を値によってキャプチャできるようになりました。以下の例では、 =
の左側にあるtask2
のキャプチャリストのp
、ラムダ本体にプライベートな新しい変数であり、元のp
を参照しないことに注意してください。
auto p = std::make_unique< int >( 1 );
auto task1 = [=] { *p = 5 ; }; // ERROR: std::unique_ptr cannot be copied
// vs.
auto task2 = [p = std::move(p)] { *p = 5 ; }; // OK: p is move-constructed into the closure object
// the original p is empty after task2 is created
この参照キャプチャを使用すると、参照される変数とは異なる名前を付けることができます。
auto x = 1 ;
auto f = [&r = x, x = x * 10 ] {
++r;
return r + x;
};
f (); // sets x to 2 and returns 12
C++14 のauto
戻り型を使用すると、コンパイラは型を推測しようとします。ラムダを使用すると、 auto
使用して戻り値の型を推測できるようになり、推測された参照または右辺値参照を返すことが可能になります。
// Deduce return type as `int`.
auto f ( int i) {
return i;
}
template < typename T>
auto & f (T& t) {
return t;
}
// Returns a reference to a deduced type.
auto g = []( auto & x) -> auto & { return f (x); };
int y = 123 ;
int & z = g(y); // reference to `y`
decltype(auto)
型指定子も、 auto
と同様に型を推定します。ただし、auto は参照と cv 修飾子を保持したまま戻り値の型を推定しますが、 auto
そうではありません。
const int x = 0 ;
auto x1 = x; // int
decltype ( auto ) x2 = x; // const int
int y = 0 ;
int & y1 = y;
auto y2 = y1; // int
decltype ( auto ) y3 = y1; // int&
int && z = 0 ;
auto z1 = std::move(z); // int
decltype ( auto ) z2 = std::move(z); // int&&
// Note: Especially useful for generic code!
// Return type is `int`.
auto f ( const int & i) {
return i;
}
// Return type is `const int&`.
decltype ( auto ) g( const int & i) {
return i;
}
int x = 123 ;
static_assert (std::is_same< const int &, decltype(f(x))>::value == 0);
static_assert (std::is_same< int , decltype(f(x))>::value == 1);
static_assert (std::is_same< const int &, decltype(g(x))>::value == 1);
decltype (C++11)
」も参照してください。
C++11 では、 constexpr
関数本体には、 typedef
、 using
、単一のreturn
ステートメントなど (ただしこれらに限定されない) 非常に限られた構文セットのみを含めることができました。 C++14 では、使用できる構文のセットが大幅に拡張され、 if
ステートメント、複数のreturn
、ループなどの最も一般的な構文が含まれます。
constexpr int factorial ( int n) {
if (n <= 1 ) {
return 1 ;
} else {
return n * factorial (n - 1 );
}
}
factorial ( 5 ); // == 120
C++14 では変数をテンプレート化できます。
template < class T >
constexpr T pi = T( 3.1415926535897932385 );
template < class T >
constexpr T e = T( 2.7182818284590452353 );
C++14 では、ユニット (関数、クラスなど) が推奨されておらず、コンパイル警告が発生する可能性があることを示す[[deprecated]]
属性が導入されています。理由が指定されている場合、それは警告に含まれます。
[[deprecated]]
void old_method ();
[[deprecated( " Use new_method instead " )]]
void legacy_method ();
chrono
およびbasic_string
の新しい組み込みリテラルを含む、標準ライブラリ タイプの新しいユーザー定義リテラル。これらは、コンパイル時に使用できることを意味するconstexpr
にすることができます。これらのリテラルの用途には、コンパイル時の整数解析、バイナリ リテラル、虚数リテラルなどがあります。
using namespace std ::chrono_literals ;
auto day = 24h;
day.count(); // == 24
std::chrono::duration_cast<std::chrono::minutes>(day).count(); // == 1440
クラス テンプレートstd::integer_sequence
コンパイル時の整数シーケンスを表します。その上にいくつかのヘルパーが構築されています。
std::make_integer_sequence<T, N>
- 型T
で0, ..., N - 1
のシーケンスを作成します。std::index_sequence_for<T...>
- テンプレート パラメーター パックを整数シーケンスに変換します。配列をタプルに変換します。
template < typename Array, std:: size_t ... I>
decltype ( auto ) a2t_impl( const Array& a, std::integer_sequence<std:: size_t , I...>) {
return std::make_tuple (a[I]...);
}
template < typename T, std:: size_t N, typename Indices = std::make_index_sequence<N>>
decltype ( auto ) a2t( const std::array<T, N>& a) {
return a2t_impl (a, Indices ());
}
次の理由により、 std::make_unique
std::unique_ptr
のインスタンスを作成する方法として推奨されます。
new
演算子を使用する必要は避けてください。foo
呼び出していたとします。 foo (std::unique_ptr<T>{ new T{}}, function_that_throws(), std::unique_ptr<T>{ new T{}});
コンパイラは、 new T{}
を自由に呼び出し、次にfunction_that_throws()
などを呼び出します。 T
の最初の構築でヒープにデータを割り当てたため、ここでリークが発生しました。 std::make_unique
使用すると、例外安全性が与えられます。
foo (std::make_unique<T>(), function_that_throws(), std::make_unique<T>());
std::unique_ptr
およびstd::shared_ptr
の詳細については、スマート ポインター (C++11) のセクションを参照してください。
オブジェクトの移動とは、そのオブジェクトが管理するリソースの所有権を別のオブジェクトに譲渡することを意味します。
移動セマンティクスの最初の利点は、パフォーマンスの最適化です。オブジェクトが一時的なものであるか、 std::move
明示的に呼び出すことによって、オブジェクトの寿命が終わりに近づくと、多くの場合、リソースを移動するためのより安価な方法が移動になります。たとえば、 std::vector
移動は、いくつかのポインタと内部状態を新しいベクトルにコピーするだけです。コピーには、ベクトルに含まれるすべての要素をコピーする必要がありますが、古いベクトルがすぐに削除される場合、これはコストがかかり、不要です。破壊されました。
また、移動により、インスタンスを転送しながら、 std::unique_ptr
(スマート ポインター) などのコピー不可能な型で、一度に管理されるリソースのインスタンスが 1 つだけであることを言語レベルで保証できるようになります。スコープ間。
右辺値参照、移動セマンティクス用の特別なメンバー関数、 std::move
、 std::forward
、 forwarding references
に関するセクションを参照してください。
C++11 では、右辺値参照と呼ばれる新しい参照が導入されています。非テンプレート型パラメーター ( int
またはユーザー定義型など) であるT
への右辺値参照は、構文T&&
使用して作成されます。右辺値参照は右辺値にのみバインドされます。
左辺値と右辺値を使用した型推定:
int x = 0 ; // `x` is an lvalue of type `int`
int & xl = x; // `xl` is an lvalue of type `int&`
int && xr = x; // compiler error -- `x` is an lvalue
int && xr2 = 0 ; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`
void f ( int & x) {}
void f ( int && x) {}
f (x); // calls f(int&)
f (xl); // calls f(int&)
f ( 3 ); // calls f(int&&)
f (std::move(x)); // calls f(int&&)
f (xr2); // calls f(int&)
f (std::move(xr2)); // calls f(int&& x)
std::move
」、 std::forward
、 forwarding references
も参照してください。
(非公式には)ユニバーサル参照とも呼ばれます。転送参照は、構文T&&
( T
はテンプレート タイプ パラメーター) またはauto&&
を使用して作成されます。これにより、完全な転送が可能になります。つまり、値のカテゴリを維持しながら引数を渡す機能です (たとえば、左辺値は左辺値のままで、一時値は右辺値として転送されます)。
転送参照を使用すると、型に応じて参照を左辺値または右辺値のいずれかにバインドできます。参照の転送は、参照の折りたたみのルールに従います。
T& &
T&
になりますT& &&
がT&
になりますT&& &
T&
になりますT&& &&
T&&
になります左辺値と右辺値を使用したauto
型推定:
int x = 0 ; // `x` is an lvalue of type `int`
auto && al = x; // `al` is an lvalue of type `int&` -- binds to the lvalue, `x`
auto && ar = 0 ; // `ar` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`
左辺値と右辺値を使用したテンプレート タイプ パラメーターの推定:
// Since C++14 or later:
void f ( auto && t) {
// ...
}
// Since C++11 or later:
template < typename T>
void f (T&& t) {
// ...
}
int x = 0 ;
f ( 0 ); // T is int, deduces as f(int &&) => f(int&&)
f (x); // T is int&, deduces as f(int& &&) => f(int&)
int & y = x;
f (y); // T is int&, deduces as f(int& &&) => f(int&)
int && z = 0 ; // NOTE: `z` is an lvalue with type `int&&`.
f (z); // T is int&, deduces as f(int& &&) => f(int&)
f (std::move(z)); // T is int, deduces as f(int &&) => f(int&&)
std::move
」、 std::forward
、 rvalue references
も参照してください。
...
構文はパラメータ パックを作成するか、パラメータ パックを展開します。テンプレートパラメーター パックは、0 個以上のテンプレート引数 (非型、型、またはテンプレート) を受け入れるテンプレート パラメーターです。少なくとも 1 つのパラメーター パックを持つテンプレートは、可変個引数テンプレートと呼ばれます。
template < typename ... T>
struct arity {
constexpr static int value = sizeof ...(T);
};
static_assert (arity<>::value == 0 );
static_assert (arity< char , short , int >::value == 3 );
これの興味深い使用法は、関数の可変引数を反復処理するためにパラメーター パックから初期化子リストを作成することです。
template < typename First, typename ... Args>
auto sum ( const First first, const Args... args) -> decltype(first) {
const auto values = {first, args...};
return std::accumulate (values. begin (), values. end (), First{ 0 });
}
sum ( 1 , 2 , 3 , 4 , 5 ); // 15
sum ( 1 , 2 , 3 ); // 6
sum ( 1.5 , 2.0 , 3.7 ); // 7.2
「中括弧付きリスト」構文を使用して作成された要素の軽量の配列のようなコンテナー。たとえば、 { 1, 2, 3 }
は、 std::initializer_list<int>
型の整数のシーケンスを作成します。オブジェクトのベクトルを関数に渡す代わりに便利です。
int sum ( const std::initializer_list< int >& list) {
int total = 0 ;
for ( auto & e : list) {
total += e;
}
return total;
}
auto list = { 1 , 2 , 3 };
sum (list); // == 6
sum ({ 1 , 2 , 3 }); // == 6
sum ({}); // == 0
コンパイル時に評価されるアサーション。
constexpr int x = 0 ;
constexpr int y = 1 ;
static_assert (x == y, " x != y " );
auto
型の変数は、初期化子の型に応じてコンパイラによって推定されます。
auto a = 3.14 ; // double
auto b = 1 ; // int
auto & c = b; // int&
auto d = { 0 }; // std::initializer_list<int>
auto && e = 1 ; // int&&
auto && f = b; // int&
auto g = new auto ( 123 ); // int*
const auto h = 1 ; // const int
auto i = 1 , j = 2 , k = 3 ; // int, int, int
auto l = 1 , m = true , n = 1.61 ; // error -- `l` deduced to be int, `m` is bool
auto o; // error -- `o` requires initializer
特に複雑な型の場合、読みやすさに非常に役立ちます。
std::vector< int > v = ...;
std::vector< int >::const_iterator cit = v.cbegin();
// vs.
auto cit = v.cbegin();
関数は、 auto
使用して戻り値の型を推測することもできます。 C++11 では、戻り値の型を明示的に指定するか、次のようにdecltype
使用して指定する必要があります。
template < typename X, typename Y>
auto add (X x, Y y) -> decltype(x + y) {
return x + y;
}
add ( 1 , 2 ); // == 3
add ( 1 , 2.0 ); // == 3.0
add ( 1.5 , 1.5 ); // == 3.0
上の例の末尾の戻り値の型は、式x + y
の宣言された型( decltype
のセクションを参照) です。たとえば、 x
が整数、 y
が double の場合、 decltype(x + y)
double になります。したがって、上記の関数は、式x + y
どのような型を生成するかに応じて型を推定します。後続の戻り値の型はそのパラメーターにアクセスでき、必要に応じてthis
アクセスできることに注意してください。
lambda
スコープ内の変数をキャプチャできる名前のない関数オブジェクトです。特徴は次のとおりです。キャプチャ リスト。オプションのパラメータのセットと、オプションの末尾の戻り値の型。そして体。キャプチャ リストの例:
[]
- 何もキャプチャしません。[=]
- 値によってスコープ内のローカル オブジェクト (ローカル変数、パラメーター) をキャプチャします。[&]
- スコープ内のローカル オブジェクト (ローカル変数、パラメーター) を参照によってキャプチャします。[this]
- this
参照してキャプチャします。[a, &b]
- オブジェクトa
値によって取得し、 b
参照によって取得します。 int x = 1 ;
auto getX = [=] { return x; };
getX (); // == 1
auto addX = [=]( int y) { return x + y; };
addX ( 1 ); // == 2
auto getXRef = [&]() -> int & { return x; };
getXRef (); // int& to `x`
デフォルトでは、コンパイラ生成のメソッドはconst
としてマークされているため、ラムダ内で値キャプチャを変更することはできません。 mutable
キーワードを使用すると、キャプチャされた変数を変更できます。キーワードはパラメータリストの後に配置されます(パラメータリストが空の場合でも存在する必要があります)。
int x = 1 ;
auto f1 = [&x] { x = 2 ; }; // OK: x is a reference and modifies the original
auto f2 = [x] { x = 2 ; }; // ERROR: the lambda can only perform const-operations on the captured value
// vs.
auto f3 = [x]() mutable { x = 2 ; }; // OK: the lambda can perform any operations on the captured value
decltype
渡された式の宣言された型を返す演算子です。 cv 修飾子と参照は、式の一部である場合には維持されます。 decltype
の例:
int a = 1 ; // `a` is declared as type `int`
decltype (a) b = a; // `decltype(a)` is `int`
const int & c = a; // `c` is declared as type `const int&`
decltype (c) d = a; // `decltype(c)` is `const int&`
decltype ( 123 ) e = 123; // `decltype(123)` is `int`
int && f = 1 ; // `f` is declared as type `int&&`
decltype (f) g = 1; // `decltype(f) is `int&&`
decltype ((a)) h = g; // `decltype((a))` is int&
template < typename X, typename Y>
auto add (X x, Y y) -> decltype(x + y) {
return x + y;
}
add ( 1 , 2.0 ); // `decltype(x + y)` => `decltype(3.0)` => `double`
decltype(auto) (C++14)
も参照してください。
意味的にはtypedef
の使用と似ていますが、 using
を使用した型エイリアスは読みやすく、テンプレートと互換性があります。
template < typename T>
using Vec = std::vector<T>;
Vec< int > v; // std::vector<int>
using String = std::string;
String s { " foo " };
C++11 では、C のNULL
マクロを置き換えるように設計された新しい null ポインター型が導入されています。 nullptr
自体はstd::nullptr_t
型で、暗黙的にポインター型に変換できますが、 NULL
とは異なり、 bool
除く整数型には変換できません。
void foo ( int );
void foo ( char *);
foo ( NULL ); // error -- ambiguous
foo ( nullptr ); // calls foo(char*)
暗黙の変換、基になる型を指定できないこと、スコープ汚染など、C スタイルの列挙型に関するさまざまな問題を解決するタイプセーフな列挙型。
// Specifying underlying type as `unsigned int`
enum class Color : unsigned int { Red = 0xff0000 , Green = 0xff00 , Blue = 0xff };
// `Red`/`Green` in `Alert` don't conflict with `Color`
enum class Alert : bool { Red, Green };
Color c = Color::Red;
属性は、 __attribute__(...)
、 __declspec
などを超える普遍的な構文を提供します。
// `noreturn` attribute indicates `f` doesn't return.
[[ noreturn ]] void f () {
throw " error " ;
}
一定の式は、コンパイル時にコンパイラによって評価される可能性のある式です。非複雑な計算のみを一定の式で実行できます(これらのルールは後のバージョンで徐々に緩和されます)。 constexpr
仕様を使用して、変数、関数などを示すことは一定の式です。
constexpr int square ( int x) {
return x * x;
}
int square2 ( int x) {
return x * x;
}
int a = square( 2 ); // mov DWORD PTR [rbp-4], 4
int b = square2( 2 ); // mov edi, 2
// call square2(int)
// mov DWORD PTR [rbp-8], eax
前のスニペットでは、呼び出しsquare
コンパイル時に実行されるときの計算が行われ、結果はコード生成に埋め込まれ、 square2
実行時に呼び出されることに注意してください。
constexpr
値は、コンパイラが評価できるが保証されているものである値とは、コンパイル時には保証されていない値です。
const int x = 123 ;
constexpr const int & y = x; // error -- constexpr variable `y` must be initialized by a constant expression
クラス付きの一定の式:
struct Complex {
constexpr Complex ( double r, double i) : re{r}, im{i} { }
constexpr double real () { return re; }
constexpr double imag () { return im; }
private:
double re;
double im;
};
constexpr Complex I ( 0 , 1 );
コンストラクターは、初期イザーリストを使用して同じクラスの他のコンストラクターを呼び出すことができます。
struct Foo {
int foo;
Foo ( int foo) : foo{foo} {}
Foo () : Foo( 0 ) {}
};
Foo foo;
foo.foo; // == 0
ユーザー定義のリテラルを使用すると、言語を拡張して独自の構文を追加できます。リテラルを作成するには、 T operator "" X(...) { ... }
関数名前X
を使用してタイプT
を返します。この関数の名前はリテラルの名前を定義していることに注意してください。アンダースコアから始まっていない文字通りの名前は予約されており、呼び出されません。リテラルが呼び出されるタイプに応じて、ユーザー定義のリテラル関数が受け入れるべきパラメーターに関するルールがあります。
摂氏を華氏に変換する:
// `unsigned long long` parameter required for integer literal.
long long operator " " _celsius( unsigned long long tempCelsius) {
return std::llround (tempCelsius * 1.8 + 32 );
}
24_celsius; // == 75
文字列から整数変換:
// `const char*` and `std::size_t` required as parameters.
int operator " " _int( const char * str, std:: size_t ) {
return std::stoi (str);
}
" 123 " _int; // == 123, with type `int`
仮想関数が別の仮想関数を上書きすることを指定します。仮想関数が親の仮想関数をオーバーライドしない場合、コンパイラエラーをスローします。
struct A {
virtual void foo ();
void bar ();
};
struct B : A {
void foo () override ; // correct -- B::foo overrides A::foo
void bar () override ; // error -- A::bar is not virtual
void baz () override ; // error -- B::baz does not override A::baz
};
仮想関数を派生クラスでオーバーライドできないこと、またはクラスを継承できないことを指定します。
struct A {
virtual void foo ();
};
struct B : A {
virtual void foo () final ;
};
struct C : B {
virtual void foo (); // error -- declaration of 'foo' overrides a 'final' function
};
クラスを継承することはできません。
struct A final {};
struct B : A {}; // error -- base 'A' is marked 'final'
コンストラクターなどの関数のデフォルトの実装を提供する、よりエレガントで効率的な方法。
struct A {
A () = default ;
A ( int x) : x{x} {}
int x { 1 };
};
A a; // a.x == 1
A a2 { 123 }; // a.x == 123
継承で:
struct B {
B () : x{ 1 } {}
int x;
};
struct C : B {
// Calls B::B
C () = default ;
};
C c; // c.x == 1
機能の削除された実装を提供するための、よりエレガントで効率的な方法。オブジェクトのコピーを防ぐのに役立ちます。
class A {
int x;
public:
A ( int x) : x{x} {};
A ( const A&) = delete ;
A& operator =( const A&) = delete ;
};
A x { 123 };
A y = x; // error -- call to deleted copy constructor
y = x; // error -- operator= deleted
容器の要素を反復するための構文砂糖。
std::array< int , 5 > a { 1 , 2 , 3 , 4 , 5 };
for ( int & x : a) x *= 2 ;
// a == { 2, 4, 6, 8, 10 }
int&
ではなく、 int
使用する場合の違いに注意してください:
std::array< int , 5 > a { 1 , 2 , 3 , 4 , 5 };
for ( int x : a) x *= 2 ;
// a == { 1, 2, 3, 4, 5 }
コピーが作成されたときにコピーコンストラクターとコピーの割り当てオペレーターが呼び出され、C ++ 11の移動セマンティクスの導入により、移動コンストラクターと移動割り当てオペレーターが移動のためにあります。
struct A {
std::string s;
A () : s{ " test " } {}
A ( const A& o) : s{o. s } {}
A (A&& o) : s{ std::move (o. s )} {}
A& operator =(A&& o) {
s = std::move (o. s );
return * this ;
}
};
A f (A a) {
return a;
}
A a1 = f(A{}); // move-constructed from rvalue temporary
A a2 = std::move(a1); // move-constructed using std::move
A a3 = A{};
a2 = std::move(a3); // move-assignment using std::move
a1 = f(A{}); // move-assignment from rvalue temporary
コンストラクターを変換すると、ブレースリストの構文の値をコンストラクター引数に変換します。
struct A {
A ( int ) {}
A ( int , int ) {}
A ( int , int , int ) {}
};
A a { 0 , 0 }; // calls A::A(int, int)
A b ( 0 , 0 ); // calls A::A(int, int)
A c = { 0 , 0 }; // calls A::A(int, int)
A d { 0 , 0 , 0 }; // calls A::A(int, int, int)
Braced Listの構文では狭窄が許可されていないことに注意してください。
struct A {
A ( int ) {}
};
A a ( 1.1 ); // OK
A b { 1.1 }; // Error narrowing conversion from double to int
コンストラクターがstd::initializer_list
受け入れる場合、代わりに呼び出されることに注意してください。
struct A {
A ( int ) {}
A ( int , int ) {}
A ( int , int , int ) {}
A (std::initializer_list< int >) {}
};
A a { 0 , 0 }; // calls A::A(std::initializer_list<int>)
A b ( 0 , 0 ); // calls A::A(int, int)
A c = { 0 , 0 }; // calls A::A(std::initializer_list<int>)
A d { 0 , 0 , 0 }; // calls A::A(std::initializer_list<int>)
これで、 explicit
仕様を使用して、変換機能を明示的にすることができます。
struct A {
operator bool () const { return true ; }
};
struct B {
explicit operator bool () const { return true ; }
};
A a;
if (a); // OK calls A::operator bool()
bool ba = a; // OK copy-initialization selects A::operator bool()
B b;
if (b); // OK calls B::operator bool()
bool bb = b; // error copy-initialization does not consider B::operator bool()
インラインネームスペースのすべてのメンバーは、それらがその親ネームスペースの一部であるかのように扱われ、機能の専門化を可能にし、バージョン化のプロセスを緩和します。これは、aがbを含む場合、cとbとcの両方がインラインネームスペースである場合、推移的なプロパティであるため、cのメンバーはAにいるかのように使用できます。
namespace Program {
namespace Version1 {
int getVersion () { return 1 ; }
bool isFirstVersion () { return true ; }
}
inline namespace Version2 {
int getVersion () { return 2 ; }
}
}
int version { Program::getVersion ()}; // Uses getVersion() from Version2
int oldVersion { Program::Version1::getVersion ()}; // Uses getVersion() from Version1
bool firstVersion { Program::isFirstVersion ()}; // Does not compile when Version2 is added
非静的なデータメンバーを宣言された場所で初期化することができ、デフォルトの初期化のコンストラクターをクリーンアップする可能性があります。
// Default initialization prior to C++11
class Human {
Human () : age{ 0 } {}
private:
unsigned age;
};
// Default initialization on C++11
class Human {
private:
unsigned age { 0 };
};
C ++ 11は、一連の直角ブラケットがオペレーターとして使用されるとき、またはWhiteSpaceを追加することなく、Typedefの終了ステートメントとして使用されることを推測できるようになりました。
typedef std::map< int , std::map < int , std::map < int , int > > > cpp98LongTypedef;
typedef std::map< int , std::map < int , std::map < int , int >>> cpp11LongTypedef;
メンバー関数は、 *this
がlvalueまたはrvalueリファレンスであるかどうかに応じて、資格を取得できるようになりました。
struct Bar {
// ...
};
struct Foo {
Bar& getBar () & { return bar; }
const Bar& getBar () const & { return bar; }
Bar&& getBar() && { return std::move (bar); }
const Bar&& getBar() const && { return std::move (bar); }
private:
Bar bar;
};
Foo foo{};
Bar bar = foo.getBar(); // calls `Bar& getBar() &`
const Foo foo2{};
Bar bar2 = foo2.getBar(); // calls `Bar& Foo::getBar() const&`
Foo{}.getBar(); // calls `Bar&& Foo::getBar() &&`
std::move (foo).getBar(); // calls `Bar&& Foo::getBar() &&`
std::move (foo2).getBar(); // calls `const Bar&& Foo::getBar() const&`
C ++ 11を使用すると、関数とLambdasがリターンタイプを指定するための代替構文を可能にします。
int f () {
return 123 ;
}
// vs.
auto f () -> int {
return 123 ;
}
auto g = []() -> int {
return 123 ;
};
この機能は、特定のリターンタイプを解決できない場合に特に役立ちます。
// NOTE: This does not compile!
template < typename T, typename U>
decltype (a + b) add(T a, U b) {
return a + b;
}
// Trailing return types allows this:
template < typename T, typename U>
auto add (T a, U b) -> decltype(a + b) {
return a + b;
}
C ++ 14では、代わりにdecltype(auto) (C++14)
を使用できます。
noexcept
仕様は、関数が例外をスローできるかどうかを指定します。 throw()
の改良バージョンです。
void func1 () noexcept ; // does not throw
void func2 () noexcept ( true ); // does not throw
void func3 () throw(); // does not throw
void func4 () noexcept ( false ); // may throw
非投げ関数は、潜在的に投げる機能を呼び出すことが許可されています。例外がスローされ、ハンドラーの検索が非投げ関数の最も外側のブロックに遭遇するときはいつでも、関数STD ::終端が呼び出されます。
extern void f (); // potentially-throwing
void g () noexcept {
f (); // valid, even if f throws
throw 42 ; // valid, effectively a call to std::terminate
}
UTF-8文字列を表すための標準タイプを提供します。
char32_t utf8_str[] = U" u0123 " ;
char16_t utf8_str[] = u" u0123 " ;
C ++ 11は、文字列リテラルを「生文字列リテラル」と宣言する新しい方法を導入します。エスケープシーケンス(タブ、ラインフィード、単一のバックスラッシュなど)から発行された文字は、フォーマットを保持しながら生で入力できます。これは、たとえば、文学的なテキストを書くのに便利です。これにより、文字列リテラルが読みやすくなり、メンテナンスを容易にすることができます。
生の文字列リテラルは、次の構文を使用して宣言されます。
R"delimiter(raw_characters)delimiter"
どこ:
delimiter
、括弧、バックスラッシュ、スペースを除くソース文字で作られたオプションの文字のシーケンスです。raw_characters
、生のキャラクターシーケンスです。閉じるシーケンス")delimiter"
を含めてはなりません。例:
// msg1 and msg2 are equivalent.
const char * msg1 = " n Hello, nt world! n " ;
const char * msg2 = R"(
Hello,
world!
)" ;
std::move
渡されたオブジェクトにリソースが転送される可能性があることを示します。移動されたオブジェクトを使用すると、不特定の状態に残ることができるため、注意して使用する必要があります(移動したオブジェクトで何ができますか?)。
std::move
の定義(移動を実行することは、RValueリファレンスへのキャストにすぎません):
template < typename T>
typename remove_reference<T>::type&& move(T&& arg) {
return static_cast < typename remove_reference<T>::type&&>(arg);
}
std::unique_ptr
の転送:
std::unique_ptr< int > p1 { new int { 0 }}; // in practice, use std::make_unique
std::unique_ptr< int > p2 = p1; // error -- cannot copy unique pointers
std::unique_ptr< int > p3 = std::move(p1); // move `p1` into `p3`
// now unsafe to dereference object held by `p1`
価値カテゴリとCV資格を維持しながら、それに渡された引数を返します。一般的なコードや工場に役立ちます。 forwarding references
と組み合わせて使用されます。
std::forward
の定義:
template < typename T>
T&& forward( typename remove_reference<T>::type& arg) {
return static_cast <T&&>(arg);
}
他のA
オブジェクトを新しいA
オブジェクトのコピーまたは移動コンストラクターに転送する機能wrapper
の例:
struct A {
A () = default ;
A ( const A& o) { std::cout << " copied " << std::endl; }
A (A&& o) { std::cout << " moved " << std::endl; }
};
template < typename T>
A wrapper (T&& arg) {
return A{std::forward<T>(arg)};
}
wrapper (A{}); // moved
A a;
wrapper (a); // copied
wrapper (std::move(a)); // moved
参照: forwarding references
、 rvalue references
。
std::thread
ライブラリは、スレッドを産んだり殺害するなど、スレッドを制御する標準的な方法を提供します。以下の例では、複数のスレッドが異なる計算を行うように生じ、その後、プログラムはそれらすべてが終了するのを待ちます。
void foo ( bool clause) { /* do something... */ }
std::vector<std::thread> threadsVector;
threadsVector.emplace_back([]() {
// Lambda function that will be invoked
});
threadsVector.emplace_back(foo, true ); // thread will run foo(true)
for ( auto & thread : threadsVector) {
thread. join (); // Wait for threads to finish
}
数値引数をstd::string
に変換します。
std::to_string ( 1.2 ); // == "1.2"
std::to_string ( 123 ); // == "123"
タイプ特性は、タイプのプロパティをクエリまたは変更するコンパイルタイムテンプレートベースのインターフェイスを定義します。
static_assert (std::is_integral< int >::value);
static_assert (std::is_same< int , int >::value);
static_assert (std::is_same<std::conditional< true , int , double >::type, int >::value);
C ++ 11は、新しいスマートポインターを紹介します: std::unique_ptr
、 std::shared_ptr
、 std::weak_ptr
。 std::auto_ptr
非推奨になり、最終的にC ++ 17で削除されます。
std::unique_ptr
は、独自のヒープに割り当てられたメモリを管理する非調整可能で可動性のあるポインターです。注:コンストラクターを使用するのではなく、 std::make_X
ヘルパー機能を使用することを好みます。 std :: make_uniqueおよびstd :: make_sharedのセクションを参照してください。
std::unique_ptr<Foo> p1 { new Foo{} }; // `p1` owns `Foo`
if (p1) {
p1-> bar ();
}
{
std::unique_ptr<Foo> p2 { std::move (p1)}; // Now `p2` owns `Foo`
f (*p2);
p1 = std::move (p2); // Ownership returns to `p1` -- `p2` gets destroyed
}
if (p1) {
p1-> bar ();
}
// `Foo` instance is destroyed when `p1` goes out of scope
std::shared_ptr
複数の所有者で共有されるリソースを管理するスマートポインターです。共有ポインターには、管理されたオブジェクトや参照カウンターなどのいくつかのコンポーネントがあるコントロールブロックがあります。すべての制御ブロックアクセスはスレッドセーフですが、管理されたオブジェクト自体を操作することはスレッドセーフではありません。
void foo (std::shared_ptr<T> t) {
// Do something with `t`...
}
void bar (std::shared_ptr<T> t) {
// Do something with `t`...
}
void baz (std::shared_ptr<T> t) {
// Do something with `t`...
}
std::shared_ptr<T> p1 { new T{}};
// Perhaps these take place in another threads?
foo (p1);
bar (p1);
baz (p1);
Chronoライブラリには、期間、時計、時点を扱う一連のユーティリティ機能とタイプが含まれています。このライブラリのユースケースの1つは、ベンチマークコードです。
std::chrono::time_point<std::chrono::steady_clock> start, end;
start = std::chrono::steady_clock::now();
// Some computations...
end = std::chrono::steady_clock::now();
std::chrono::duration< double > elapsed_seconds = end - start;
double t = elapsed_seconds.count(); // t number of seconds, represented as a `double`
タプルは、不均一値の固定サイズのコレクションです。 std std::tie
を使用して開梱するか、 std::get
を使用して、 std::tuple
の要素にアクセスします。
// `playerProfile` has type `std::tuple<int, const char*, const char*>`.
auto playerProfile = std::make_tuple( 51 , " Frans Nielsen " , " NYI " );
std::get< 0 >(playerProfile); // 51
std::get< 1 >(playerProfile); // "Frans Nielsen"
std::get< 2 >(playerProfile); // "NYI"
LValueの参照のタプルを作成します。 std::pair
とstd::tuple
オブジェクトを開梱するのに役立ちます。 std::ignore
。 C ++ 17では、代わりに構造化されたバインディングを使用する必要があります。
// With tuples...
std::string playerName;
std::tie (std::ignore, playerName, std::ignore) = std::make_tuple( 91 , " John Tavares " , " NYI " );
// With pairs...
std::string yes, no;
std::tie (yes, no) = std::make_pair( " yes " , " no " );
std::array
Cスタイル配列の上に構築されたコンテナです。ソートなどの一般的なコンテナ操作をサポートします。
std::array< int , 3 > a = { 2 , 1 , 3 };
std::sort (a.begin(), a.end()); // a == { 1, 2, 3 }
for ( int & x : a) x *= 2 ; // a == { 2, 4, 6 }
これらのコンテナは、操作を検索、挿入、削除するために、平均時間の複雑さを維持します。一定の時間の複雑さを実現するために、要素をバケツにハッシュすることにより、速度を犠牲にします。 4つの順序付けられていないコンテナがあります。
unordered_set
unordered_multiset
unordered_map
unordered_multimap
std::make_shared
次の理由により、 std::shared_ptr
sのインスタンスを作成するための推奨される方法です。
new
オペレーターを使用する必要はありません。foo
と呼んでいたとします: foo (std::shared_ptr<T>{ new T{}}, function_that_throws(), std::shared_ptr<T>{ new T{}});
コンパイラはnew T{}
、次にfunction_that_throws()
などを無料で呼び出すことができます... T
の最初の構造でヒープにデータを割り当てたため、ここにリークが導入されました。 std::make_shared
使用すると、例外セーフティが与えられます。
foo (std::make_shared<T>(), function_that_throws(), std::make_shared<T>());
std::shared_ptr{ new T{} }
を呼び出すとき、 T
にメモリを割り当てる必要があります。その後、共有ポインターでポインター内のコントロールブロックにメモリを割り当てる必要があります。 std::unique_ptr
およびstd::shared_ptr
の詳細については、スマートポインターのセクションを参照してください。
std::ref(val)
valの参照を保持するタイプstd::reference_wrapper
のオブジェクトを作成するために使用されます。タイプの控除のためにコンパイル&
コンパイルされない、または&
されない通常の参照の場合に使用されます。 std::cref
は似ていますが、作成された参照ラッパーはVALへのconst参照を保持します。
// create a container to store reference of objects.
auto val = 99 ;
auto _ref = std::ref(val);
_ref++;
auto _cref = std::cref(val);
// _cref++; does not compile
std::vector<std::reference_wrapper< int >>vec; // vector<int&>vec does not compile
vec.push_back(_ref); // vec.push_back(&i) does not compile
cout << val << endl; // prints 100
cout << vec[ 0 ] << endl; // prints 100
cout << _cref; // prints 100
C ++ 11は、C ++のメモリモデルを導入します。これは、スレッドと原子動作のライブラリサポートを意味します。これらの操作には、アトミック負荷/ストア、比較とスワップ、原子フラグ、約束、先物、ロック、および条件変数が含まれます(ただしに限定されていません)。
std :: threadのセクションを参照してください
std::async
与えられた関数を非同期または怠lazilyに回避し、その関数呼び出しの結果を保持するstd::future
を返します。
最初のパラメーターは、次のポリシーです。
std::launch::async | std::launch::deferred
非同期実行を実行するか怠zyな評価を実行するかを実装することです。std::launch::async
新しいスレッドで呼び出し可能なオブジェクトを実行します。std::launch::deferred
現在のスレッドで怠zyな評価を実行します。 int foo () {
/* Do something here, then return the result. */
return 1000 ;
}
auto handle = std::async(std::launch::async, foo); // create an async task
auto result = handle.get(); // wait for the result
std::begin
and std::end
free functionsを追加して、容器の容器の復元者を汎用に戻します。これらの関数は、メンバー関数をbegin
およびend
ない生の配列でも動作します。
template < typename T>
int CountTwos ( const T& container) {
return std::count_if ( std::begin (container), std::end (container), []( int item) {
return item == 2 ;
});
}
std::vector< int > vec = { 2 , 2 , 43 , 435 , 4543 , 534 };
int arr[ 8 ] = { 2 , 43 , 45 , 435 , 32 , 32 , 32 , 32 };
auto a = CountTwos(vec); // 2
auto b = CountTwos(arr); // 1
アンソニー・カランドラ
参照:https://github.com/anthonycalandra/modern-cpp-features/graphs/contributors
mit