簡體   English   中英

C ++如何移動或交換對<const T, U> ?

[英]C++ How can I move or swap pair<const T, U>?

我正在寫一個 B-Tree 類。 我想支持所有四種情況,例如std::setstd::multisetstd::mapstd::multimap

我驗證了我的代碼在前兩種情況下可以正常工作。 問題在於后兩者。 他們的聲明是這樣的:

template <typename T>
concept Containable = std::is_same_v<std::remove_cvref_t<T>, T>;

using index_t = std::ptrdiff_t;

template <Containable K, index_t t = 2, typename Comp = std::ranges::less,
          typename Alloc = std::allocator<K>>
using BTreeSet = detail::BTreeBase<K, K, t, Comp, false, Alloc>;

template <Containable K, index_t t = 2, typename Comp = std::ranges::less,
          typename Alloc = std::allocator<K>>
using BTreeMultiSet = detail::BTreeBase<K, K, t, Comp, true, Alloc>;

template <Containable K, Containable V, index_t t = 2,
          typename Comp = std::ranges::less,
          typename Alloc = std::allocator<std::pair<const K, V>>>
using BTreeMap = detail::BTreeBase<K, std::pair<const K, V>, t, Comp, false, Alloc>;

template <Containable K, Containable V, index_t t = 2,
          typename Comp = std::ranges::less,
          typename Alloc = std::allocator<std::pair<const K, V>>>
using BTreeMultiMap =
    detail::BTreeBase<K, std::pair<const K, V>, t, Comp, true, Alloc>;

BTreeBase是這樣的

template <Containable K, typename V, index_t t, typename Comp, bool AllowDup,
          typename Alloc>
requires(t >= 2) class BTreeBase {

// ... details ...
};

對於BTreeMapvalue_typestd::pair<const K, V> 對於關聯容器,通過取消引用迭代器更改鍵是不可接受的。

這行讓我很頭疼:

x->keys_[i] = std::move(y->keys_[t - 1]);

它不編譯。 std::iter_swapstd::swap不起作用

這里xyBTreeBase::Nodekeys_std::vector<value_type, Alloc>

標准庫容器std::mapstd::unordered_map使用相同的方法,但它們沒有這個問題,因為它基於紅黑樹和哈希表,所以一個節點只有一個鍵,所以你可以移動一個節點,而不是一個鍵。

但 B-Tree 是另一種野獸。 一個節點有許多密鑰,並且應該可以在節點之間移動或交換密鑰。 (用戶仍然不應該被允許從外部更改密鑰)

我該如何處理?

我發現的唯一方法是不使用std::pair<const K, V>

這是我更改的設計:

template <typename> struct TreePairRef {};

template <typename T, typename U> struct TreePairRef<std::pair<T, U>> {
  using type = std::pair<const T &, U &>;
};

template <typename TreePair>
using PairRefType = TreePairRef<TreePair>::type;

template <typename> struct TreeRefBase {};

template <typename T, typename U> struct TreeRefBase<std::pair<const T&, U&>> {
  using type = std::pair<T, U>;
};

template <typename TreeRef>
using RefBaseType = typename TreeRefBase<TreeRef>::type;

更改迭代器:

  template <typename T, bool Const, bool isRef> struct BTreeIterator {
    using difference_type = std::ptrdiff_t;
    using value_type = std::conditional_t<isRef, RefBaseType<T>, T>;
    using pointer = std::conditional_t<Const, const value_type*, value_type*>;
    using reference = std::conditional_t<Const, const value_type&, std::conditional_t<isRef, T, value_type&>>;
    using node_type = Node *;
    using iterator_category = std::bidirectional_iterator_tag;
    using iterator_concept = std::iterator_category;

樹型設計:

// invariant: V is either K or std::pair<const K, Value> for some Value type.
  static constexpr bool is_set_ = std::is_same_v<K, V>;

  using value_type = V;
  using reference_type = std::conditional_t<is_set_, const V &, PairRefType<V>>;
  using iterator_type = BTreeIterator<std::conditional_t<is_set_, value_type, reference_type>, is_set_, !is_set_>;
  using const_iterator_type = BTreeIterator<std::conditional_t<is_set_, value_type, reference_type>, true, !is_set_>;
  using reverse_iterator_type = std::reverse_iterator<std::iterator_type>;
  using const_reverse_iterator_type = std::reverse_iterator<std::const_iterator_type>;

此設計無需更多技巧即可工作

  namespace fc = frozenca;
  fc::BTreeMap<std::string, int> tree;

  tree["a"] = 3;
  tree["aaaa"] = 4;
  tree["bas"] = 6;
  tree["asdf"] = 6;

  for (const auto& [k, v] : tree) {
    std::cout << k << ' ' << v << '\n';
  }

  tree["asdf"] = 3333;

  std::cout << tree["asdf"] << '\n';

輸出

a 3
aaaa 4
asdf 6
bas 6
3333

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM