C++ 对于不满足 require 子句的情况,跳过模板实例化



我正在写一些类似STL红黑树的东西来练习编码。

我的TreeSet,TreeMap,TreeMultiSet,TreeMultiMap都共享RedBlackTree的实现,其声明如下:

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>;

我在编写operator[]时遇到了一个问题,它应该仅为TreeMap实例化(这与STL相同,仅为四个有序关联容器中的std::map提供operator[])

我的声明是这样的:

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)

但是如果RedBlackTree被实例化为TreeSet(其中V = K所以!std::is_same_v<K, V>不成立),则编译失败。

编译器的抱怨是V = K = int(因为我将RedBlackTree实例化为TreeSet<int>),所以V没有second

为什么编译器不跳过这个函数的实例化?requires条款不满足…

编译器:MSVC 19.30

V是由类固定的,所以你不能在成员函数中对它使用SFINAE。

你可以引入额外的模板参数作为解决方法:

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);

或使用auto/decltype(auto)

template <typename V2 = V, typename T>
auto& operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup);

自我回答:

我发现这个解决了问题:

template <typename T>
auto& operator[](T&& raw_key) requires (!std::is_same_v<K, V> && !AllowDup)

相关内容