Skip to content

Commit

Permalink
flat_map : try_emplaceを追加 #1078
Browse files Browse the repository at this point in the history
  • Loading branch information
faithandbrave committed Jun 23, 2023
1 parent 2ba5e13 commit 2c9f635
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 10 deletions.
2 changes: 1 addition & 1 deletion reference/flat_map/flat_map.md
Expand Up @@ -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 |
Expand Down
2 changes: 1 addition & 1 deletion reference/flat_map/flat_map/emplace.md
Expand Up @@ -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) | キーが存在しない場合のみ要素を直接構築する |
4 changes: 2 additions & 2 deletions reference/flat_map/flat_map/emplace_hint.md
Expand Up @@ -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) の対象となって変更されてしまっている可能性があるため、注意が必要である。
## 例
Expand Down Expand Up @@ -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) | キーが存在しない場合のみ要素を直接構築する |

12 changes: 6 additions & 6 deletions reference/flat_map/flat_map/op_at.md
Expand Up @@ -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]


Expand Down Expand Up @@ -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]

### 出力
```
Expand Down
178 changes: 178 additions & 0 deletions 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 <class... Args>
pair<iterator, bool>
try_emplace(const key_type& k,
Args&&... args); // (1) C++23

template <class... Args>
pair<iterator, bool>
try_emplace(key_type&& k,
Args&&... args); // (2) C++23

template <class... Args>
iterator
try_emplace(const_iterator hint,
const key_type& k,
Args&&... args); // (3) C++23

template <class... Args>
iterator
try_emplace(const_iterator hint,
key_type&& k,
Args&&... args); // (4) C++23

template <class K, class... Args>
pair<iterator, bool>
try_emplace(K&& k
Args&&... args); // (5) C++23

template <class K, class... Args>
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)`<mapped_type, Args...>`が`true`であること
- (5), (6) :
- `Compare::is_transparent`が有効な式であること
- [`is_constructible_v`](/reference/type_traits/is_constructible.md)`<key_type, K>`が`true`であること
- (5) :
- [`is_convertible_v`](/reference/type_traits/is_convertible.md)`<K&&, const_iterator>`と[`is_convertible_v`](/reference/type_traits/is_convertible.md)`<K&&, iterator>`がどちらも`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<decltype(k)>(k));
c.values.emplace(value_it, std::forward<Args>(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>(k));
c.values.emplace(value_it, std::forward<Args>(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 <iostream>
#include <flat_map>
#include <memory>
#include <utility>

int main()
{
std::flat_map<int, std::unique_ptr<int>> fm;

auto u1 = std::make_unique<int>(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<int>(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) | ヒントを使って要素を直接構築する |

0 comments on commit 2c9f635

Please sign in to comment.