From 2c9f635eff6128691a72fb7312df6fe1f69deb8e Mon Sep 17 00:00:00 2001 From: Akira Takahashi Date: Fri, 23 Jun 2023 13:50:47 +0900 Subject: [PATCH] =?UTF-8?q?flat=5Fmap=20:=20try=5Femplace=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20#1078?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reference/flat_map/flat_map.md | 2 +- reference/flat_map/flat_map/emplace.md | 2 +- reference/flat_map/flat_map/emplace_hint.md | 4 +- reference/flat_map/flat_map/op_at.md | 12 +- reference/flat_map/flat_map/try_emplace.md | 178 ++++++++++++++++++++ 5 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 reference/flat_map/flat_map/try_emplace.md diff --git a/reference/flat_map/flat_map.md b/reference/flat_map/flat_map.md index a64b6db0b..fad991010 100644 --- a/reference/flat_map/flat_map.md +++ b/reference/flat_map/flat_map.md @@ -63,7 +63,7 @@ namespace std { | [`insert_range`](flat_map/insert_range.md.nolink) | Rangeを挿入する | C++23 | | [`emplace`](flat_map/emplace.md) | 要素を直接構築する | C++23 | | [`emplace_hint`](flat_map/emplace_hint.md) | ヒントを使って要素を直接構築する | C++23 | -| [`try_emplace`](flat_map/try_emplace.md.nolink) | キーが存在しない場合のみ要素を直接構築する | C++23 | +| [`try_emplace`](flat_map/try_emplace.md) | キーが存在しない場合のみ要素を直接構築する | C++23 | | [`erase`](flat_map/erase.md) | 要素を削除する | C++23 | | [`swap`](flat_map/swap.md.nolink) | コンテンツを交換する | C++23 | | [`extract`](flat_map/extract.md.nolink) | キーのコンテナ、値のコンテナを取得する | C++23 | diff --git a/reference/flat_map/flat_map/emplace.md b/reference/flat_map/flat_map/emplace.md index 398b43084..b87c0a203 100644 --- a/reference/flat_map/flat_map/emplace.md +++ b/reference/flat_map/flat_map/emplace.md @@ -135,5 +135,5 @@ CCC : (1, 2) | [`flat_map::insert`](insert.md.nolink) | 要素を挿入する | | [`flat_map::insert_or_assign`](insert_or_assign.md.nolink) | 要素を挿入、あるいは代入する | | [`flat_map::emplace_hint`](emplace_hint.md) | ヒントを使って要素を直接構築する | -| [`flat_map::try_emplace`](try_emplace.md.nolink) | キーが存在しない場合のみ要素を直接構築する | +| [`flat_map::try_emplace`](try_emplace.md) | キーが存在しない場合のみ要素を直接構築する | diff --git a/reference/flat_map/flat_map/emplace_hint.md b/reference/flat_map/flat_map/emplace_hint.md index c9516eae4..7a016946b 100644 --- a/reference/flat_map/flat_map/emplace_hint.md +++ b/reference/flat_map/flat_map/emplace_hint.md @@ -28,7 +28,7 @@ iterator emplace_hint(const_iterator hint, Args&&... args); ## 備考 -- [`try_emplace`](try_emplace.md.nolink) と異なり、たとえ要素が挿入されなかった場合でも `value_type` 型のオブジェクトが構築される可能性があり、結果として引数 `args` が [`move`](/reference/utility/move.md) の対象となって変更されてしまっている可能性があるため、注意が必要である。 +- [`try_emplace`](try_emplace.md) と異なり、たとえ要素が挿入されなかった場合でも `value_type` 型のオブジェクトが構築される可能性があり、結果として引数 `args` が [`move`](/reference/utility/move.md) の対象となって変更されてしまっている可能性があるため、注意が必要である。 ## 例 @@ -78,5 +78,5 @@ int main() | [`flat_map::insert`](insert.md.nolink) | 要素を挿入する | | [`flat_map::insert_or_assign`](insert_or_assign.md.nolink) | 要素を挿入、あるいは代入する | | [`flat_map::emplace`](emplace.md) | 要素を直接構築する | -| [`flat_map::try_emplace`](try_emplace.md.nolink) | キーが存在しない場合のみ要素を直接構築する | +| [`flat_map::try_emplace`](try_emplace.md) | キーが存在しない場合のみ要素を直接構築する | diff --git a/reference/flat_map/flat_map/op_at.md b/reference/flat_map/flat_map/op_at.md index df611e9bd..113fb30e2 100644 --- a/reference/flat_map/flat_map/op_at.md +++ b/reference/flat_map/flat_map/op_at.md @@ -30,20 +30,20 @@ mapped_type& operator[](K&& x); // (3) C++23 ```cpp return try_emplace(x).first->second; ``` - * try_emplace[link try_emplace.md.nolink] + * try_emplace[link try_emplace.md] - (2) : 以下と等価 ```cpp return try_emplace(std::move(x)).first->second; ``` - * try_emplace[link try_emplace.md.nolink] + * try_emplace[link try_emplace.md] * std::move[link /reference/utility/move.md] - (3) : 以下と等価 ```cpp return try_emplace(std::forward(x)).first->second; ``` - * try_emplace[link try_emplace.md.nolink] + * try_emplace[link try_emplace.md] * std::forward[link /reference/utility/forward.md] @@ -75,9 +75,9 @@ int main() fm[2] = 'b'; } ``` -* m[1][color ff0000] -* m[2][color ff0000] -* m.insert[link insert.md.nolink] +* fm[1][color ff0000] +* fm[2][color ff0000] +* fm.insert[link insert.md.nolink] ### 出力 ``` diff --git a/reference/flat_map/flat_map/try_emplace.md b/reference/flat_map/flat_map/try_emplace.md new file mode 100644 index 000000000..5a5d8c721 --- /dev/null +++ b/reference/flat_map/flat_map/try_emplace.md @@ -0,0 +1,178 @@ +# try_emplace +* flat_map[meta header] +* std[meta namespace] +* flat_map[meta class] +* function template[meta id-type] +* cpp23[meta cpp] + +```cpp +template +pair + try_emplace(const key_type& k, + Args&&... args); // (1) C++23 + +template +pair + try_emplace(key_type&& k, + Args&&... args); // (2) C++23 + +template +iterator + try_emplace(const_iterator hint, + const key_type& k, + Args&&... args); // (3) C++23 + +template +iterator + try_emplace(const_iterator hint, + key_type&& k, + Args&&... args); // (4) C++23 + +template +pair + try_emplace(K&& k + Args&&... args); // (5) C++23 + +template +iterator + try_emplace(const_iterator hint, + K&& k, + Args&&... args); // (6) C++23 +``` +* pair[link /reference/utility/pair.md] + +## 概要 +指定されたキーが存在しない場合のみ要素を直接構築で挿入する。 + +引数 `k` と等価のキーを持つ要素が存在しない場合、コンテナに新しい要素を挿入する。要素は引数からコンテナ内に直接構築されるため、構築されたオブジェクトはコピーもムーブもされない。 +なお、本メンバ関数は [`emplace`](emplace.md) や [`emplace_hint`](emplace_hint.md) 等と異なり、引数 `k` と等価のキーを持つ要素が既に存在する場合には、`k` や `args` がムーブされてしまうことはない。 + +引数 `hint` は、`k` を検索する際のヒントに使用される。 + +- (1) : 指定されたキーが存在しない場合に、要素を直接構築で挿入する +- (2) : 指定された一時オブジェクトのキーが存在しない場合に、要素を直接構築で挿入する +- (3) : キーを検索するヒントを指定し、指定されたキーが存在しない場合に、要素を直接構築で挿入する +- (4) : キーを検索するヒントを指定し、指定された一時オブジェクトのキーが存在しない場合に、要素を直接構築で挿入する +- (5) : `key_type`と比較可能なキーが指定され、対応する存在しない場合に、要素を直接構築で挿入する +- (6) : keyを研削するヒントと`key_type`と比較可能なキーが指定され、対応する存在しない場合に、要素を直接構築で挿入する + + +## テンプレートパラメータ制約 +- [`is_constructible_v`](/reference/type_traits/is_constructible.md)``が`true`であること +- (5), (6) : + - `Compare::is_transparent`が有効な式であること + - [`is_constructible_v`](/reference/type_traits/is_constructible.md)``が`true`であること +- (5) : + - [`is_convertible_v`](/reference/type_traits/is_convertible.md)``と[`is_convertible_v`](/reference/type_traits/is_convertible.md)``がどちらも`false`であること + +なお、規格に記載はないが、`hint` は [`emplace_hint`](emplace_hint.md) と同様、コンテナの有効な読み取り専用イテレータである必要があるものと思われる。 + + +## 事前条件 +- (5), (6) : `k`から`key_type`への変換は、[`find`](find.md)`(k) ==` [`find`](find.md)`(u)`が`true`となるオブジェクト`u`を構築する + + +## 効果 +`k` と同値のキーを持つ要素を持っている場合、何もしない(引数への副作用もない)。そうでなければ、以下と等価: + +- (1), (2), (3), (4) : + ```cpp + auto key_it = ranges::upper_bound(c.keys, k, compare); + auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); + c.keys.insert(key_it, std::forward(k)); + c.values.emplace(value_it, std::forward(args)...); + ``` + * c.keys[link containers.md] + * c.values[link containers.md] + * ranges::upper_bound[link /reference/algorithm/ranges_upper_bound.md] + * begin()[link /reference/vector/vector/begin.md] + * distance[link /reference/iterator/distance.md] + * insert[link /reference/vector/vector/insert.md] + * emplace[link /reference/vector/vector/emplace.md] + * std::forward[link /reference/utility/forward.md] + +- (5), (6) : + ```cpp + auto key_it = ranges::upper_bound(c.keys, k, compare); + auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); + c.keys.emplace(key_it, std::forward(k)); + c.values.emplace(value_it, std::forward(args)...); + ``` + * c.keys[link containers.md] + * c.values[link containers.md] + * ranges::upper_bound[link /reference/algorithm/ranges_upper_bound.md] + * begin()[link /reference/vector/vector/begin.md] + * distance[link /reference/iterator/distance.md] + * emplace[link /reference/vector/vector/emplace.md] + * std::forward[link /reference/utility/forward.md] + + +## 戻り値 +- (1), (2), (5) : イテレータと `bool` 値の [`pair`](/reference/utility/pair.md) を返す。 + - 挿入された場合には、`first` に挿入された要素へのイテレータ、`second` に `true` が設定される。 + - 挿入されなかった場合には、`first` に `k` と等価のキーを持つ既存の要素へのイテレータ、`second` に `false` が設定される。 +- (3), (4), (6) : + - 挿入された場合には、挿入された要素へのイテレータを返す。 + - 挿入されなかった場合には、`k` と等価のキーを持つ既存の要素へのイテレータを返す。 + + +## 計算量 +- (1), (2), (5) : [`emplace`](emplace.md) と同じ +- (3), (4), (6) : [`emplace_hint`](emplace_hint.md) と同じ + + +## 備考 +- 概要に記載されているように、本メンバ関数は指定されたキーと等価の要素が既に存在する場合には、引数に副作用が発生しない。 + 一方、[`emplace`](emplace.md)、[`emplace_hint`](emplace_hint.md)、[`insert`](insert.md.nolink) にはそのような規定は無く、挿入がされなかった場合でも引数に副作用(引数からのムーブ)が発生してしまう可能性があるため、注意が必要である。 + + +## 例 +```cpp example +#include +#include +#include +#include + +int main() +{ + std::flat_map> fm; + + auto u1 = std::make_unique(114); + auto [it1, b1] = fm.try_emplace(42, std::move(u1)); + std::cout << std::boolalpha << (u1.get() == nullptr) << ", " << *it1->second << ", " << b1 << '\n'; + + auto u2 = std::make_unique(514); + auto [it2, b2] = fm.try_emplace(42, std::move(u2)); + std::cout << std::boolalpha << (u2.get() == nullptr) << ", " << *it2->second << ", " << b2 << '\n'; +} +``` +* try_emplace[color ff0000] +* get[link /reference/memory/unique_ptr/get.md] +* std::move[link /reference/utility/move.md] + +#### 出力 +``` +true, 114, true +false, 114, false +``` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 + +| 名前 | 説明 | +|------------------------------------------------|--------------------------------------------| +| [`flat_map::insert`](insert.md.nolink) | 要素を挿入する | +| [`flat_map::insert_or_assign`](insert_or_assign.md.nolink) | 要素を挿入、あるいは代入する | +| [`flat_map::emplace`](emplace.md) | 要素を直接構築する | +| [`flat_map::emplace_hint`](emplace_hint.md) | ヒントを使って要素を直接構築する | +