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)
