I'm writing something like STL red-black tree for practicing coding.
My TreeSet
, TreeMap
, TreeMultiSet
, TreeMultiMap
all share implementation of RedBlackTree
, whose declaration is like this:
template <Containable K, typename V, typename Comp, bool AllowDup>
requires std::invocable<Comp, K, K>
class RedBlackTree {
// ...
};
template <Containable K, typename Comp = std::less<K>>
using TreeSet = RedBlackTree<K, K, Comp, false>;
template <Containable K, typename Comp = std::less<K>>
using TreeMultiSet = RedBlackTree<K, K, Comp, true>;
template <Containable K, Containable V, typename Comp = std::less<K>>
using TreeMap = RedBlackTree<K, std::pair<const K, V>, Comp, false>;
template <Containable K, Containable V, typename Comp = std::less<K>>
using TreeMultiMap = RedBlackTree<K, std::pair<const K, V>, Comp, true>;
I have a problem when writing operator[]
, which should be instantiated only for TreeMap
(this is the same as STL that provides operator[]
only for std::map
among four ordered associative containers)
My declaration is like this:
template <typename T>
std::add_lvalue_reference_t<decltype(std::declval<V>().second)>
operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup)
But it fails to compile if RedBlackTree
was instantiated as TreeSet
(where V = K
so !std::is_same_v<K, V>
does not hold).
The compiler's complain is that V = K = int
(because I instantiated RedBlackTree
as TreeSet<int>
), so V
does not have second
.
Why the compiler doesn't skip instantiation of this function? requires
clause isn't satisfied...
Compiler: MSVC 19.30
CodePudding user response:
V
is fixed by the class, so you cannot use SFINAE on it in member function.
You might introduce extra template parameter as workaround:
template <typename V2 = V, typename T>
std::add_lvalue_reference_t<typename V2::second_type>
operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup);
or use auto
/decltype(auto)
template <typename V2 = V, typename T>
auto& operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup);
CodePudding user response:
Self-answer:
I found that this solves the problem:
template <typename T>
auto& operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup)