簡體   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