【问题标题】:How does std::greater<> wоrk in a set?std::greater<> 如何在集合中工作?
【发布时间】:2021-03-19 12:20:16
【问题描述】:

我知道 std::greater 是如何工作的。但是当我从 C++14 开始阅读 std::greater 的 API 时,它的默认类型是 void。因此,如果我们不将任何模板参数传递给更大,它默认为 void,如下所示。但是结果是按降序排列的。

#include <iostream>
#include <set>

template< class T = void >
struct greater;

int main()
{
    std::set<int, std::greater<>> s {4, 5, 6, 7}; // This transforms to std::set<int, std::greater<void>>
}

有人能解释一下这个专业是如何工作的吗?

【问题讨论】:

    标签: c++ c++14


    【解决方案1】:

    它的工作原理是让调用运算符成为函数模板而不是函数。将旧版本与新专业进行比较:

    // greater<T>
    bool operator()( const T& lhs, const T& rhs ) const;
    
    // greater<void> i.e. greater<>
    template< class T, class U>
    auto operator()( T&& lhs, U&& rhs ) const;
    

    让这个伟大的原因在于能够比较不同类型的对象。

    这是至关重要的,例如在给定字符串视图的情况下,您需要查找等效的 std::string 是否存储在集合中。能够将字符串视图与std::string 进行比较允许我们不从该字符串视图创建字符串。这很好,因为 std::string 的创建成本可能很高。

    使用旧的比较器,它只能将std::string 与另一个std::string 进行比较,在这种情况下,我们必须创建一个std::string 才能从一组std::string 中查找它。

    【讨论】:

      【解决方案2】:

      基本思想是将特定类型的实例化推迟到模板化operator() 的调用,而不是特定类型的实例化greater

      假设您想将重载集传递给函数,以便您可以执行以下操作:

      template <typename F>
      void foo(F f){
          f(std::string{});  
          f(42);             
      }
      

      您不能将重载集传递给foo。您也不能将类模板传递给foo(不实例化它)。但是你可以用模板化的operator()写一个类:

      struct bar {
          template <typename T>
          void operator()(T t) {}
      };
      
      
      int main() {
        foo(bar{});  
      }
      

      在您的情况下,传递 greater&lt;&gt; 而不是 greater&lt;int&gt; 主要是为了方便,但想法是一样的。 greater&lt;&gt; 有一个模板化的operator()

      PS:...我错过了greater&lt;&gt;::operator() 的一个关键优势(在this answer 中有详细说明)。 greater&lt;&gt; 允许您比较不同类型的元素,即使它们之间没有隐式转换或者您不想触发转换(当然您仍然需要一个可行的&gt;)。

      【讨论】:

      • 实例化模板函数也比新类型 AFAICR 更快。
      • @einpoklum 在greater它仍然需要实例化的greater&lt;void&gt; 加上它需要实例化的operator() 的情况下很好。不过有趣的一点,如果你知道一些参考资料,我很乐意阅读。
      • Odin Holmes 在 Code::Dive 2017 中的演讲,The fastest meta-programming in the west
      • @einpoklum 好话。糟糕的配色方案,但除此之外非常出色。不过,我认为您记错了,根据“Bob”的说法,实例化一个函数的成本更高(~43:20)。
      猜你喜欢
      • 2021-10-29
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 2021-01-07
      相关资源
      最近更新 更多