繁体   English   中英

为什么 std::compare_three_way 不是模板结构/函子

[英]Why std::compare_three_way is not a template struct/functor

例如std::less的比较被定义为模板结构

template< class T = void >
struct less;

std::compare_three_way被定义为一个普通的结构体,它的operator()是一个模板函数。 (来自 MSVC 的代码)

struct compare_three_way {
    template <class _Ty1, class _Ty2>
        requires three_way_comparable_with<_Ty1, _Ty2> // TRANSITION, GH-489
    constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
        noexcept(noexcept(_STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right))) /* strengthened */ {
        return _STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right);
    }

    using is_transparent = int;
};

那么为什么std::compare_three_way不是模板结构呢?

template <class _Ty1, class _Ty2>
    requires three_way_comparable_with<_Ty1, _Ty2>
struct compare_three_way {
    constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const; 
};

顺便说一句,我可以在我自己的容器实现中用std::three_way_compare替换std::less<T> ,比如 C# 中的Comparer<T>

原始std::less (及其朋友)的比较定义如下:

bool operator()( const T& lhs, const T& rhs ) const;

由于此函数调用运算符不是模板,因此它只能比较用于实例化std::less模板的类型的对象。

在后来的语言修订版中,这些比较器通过特殊化std::less<>进行了扩展,以通过对函数调用运算符本身进行模板化来支持比较不同类型的对象:

template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
  -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs));
    

在大多数用例中,这在很大程度上淘汰了同构版本( std::less<T> ),因为它是等效的,或者由于不强制转换为公共类型而更有效。 保留旧的同类比较器以实现向后兼容性。

当提出std::compare_three_way时,异构查找是一个存在的东西,因此从未引入同构版本。

在模板中使用它,例如std::set<T> std::less<T> std::set<T>

您可以在std::set<T>std::set<U>等中使用std::compare_three_way (比喻),就像您可以使用std::less<> 您(可能)不需要std::less<T>std::less<U> - 也不需要不存在的std::compare_three_way<T>

由于看起来std::compare_three_way执行转发,因此当模板参数用于struct时它无法工作。 C++ 标准部分 13.10.3.2 §3

转发引用是对不代表类模板的模板参数的cv 非限定模板参数的右值引用(在类模板参数推导期间 ([over.match.class.deduct]))。

因此,这里_Ty1&&_Ty2&&只是右值引用,没有办法正确转发它们:

template <class _Ty1, class _Ty2>
    requires three_way_comparable_with<_Ty1, _Ty2>
struct compare_three_way {
    constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const; 
};

上面声明的模板结构只接受右值表达式作为其操作数,这不会太有用。 使这个struct可用的唯一方法是使参数成为const引用。 MSVC 实现者选择了转发方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM