【问题标题】:Is there something like a "default comparator"?有没有类似“默认比较器”的东西?
【发布时间】:2015-03-17 15:31:01
【问题描述】:

我编写了一个包含 std::vector 的模板,以确保该向量始终是排序的:

template <typename T> class SortedVector{
public:    
    SortedVector(bool (*comparator)(T,T)=DefaultComparator<T>){
        this->comparator = comparator;
    }
    void insertValue(T newElement){            
        vect.insert(std::lower_bound(
           vect.begin(),vect.end(),newElement,comparator),newElement);
    }
private:
    std::vector<T> vect;
    bool (*comparator)(T,T);
};

我希望能够使用自定义比较器,但在大多数情况下,只需使用 T&lt; 运算符就可以了。但是,我没有找到比使用它更好的方法

template <typename T> bool DefaultComparator(T a,T b){return a<b;}

作为默认参数。

也许这是一个愚蠢的问题...如果不定义我自己的DefaultComparator,难道没有更好的方法来获得相同的结果吗?

我不能使用 C++11。

【问题讨论】:

  • 使用std::less。如果没有,自己写一个也很简单。
  • 我喜欢的一个变体是vector,只有当人们阅读它时才会排序。写入它不会对其进行排序。因此,您跟踪前缀排序位置的“高水位”标记,并在阅读时首先对“未排序”部分进行排序,然后与“已排序”部分进行合并。如果您的用例是“添加一堆数据,然后大量检查”,而不是“编辑、检查、编辑、检查”,那么这会产生非常好的性能。您的实现在两者上的性能都非常差。
  • @Yakk 我对这个类的实际应用是我必须遍历数百万个元素(太多且太大而无法放入任何合理的向量)并只保留N 最低的元素。因此,首先填充然后排序不是一种选择,否则会导致一些过于复杂的事情,因为无论如何从文件中读取这些元素而不是其他任何东西都会减慢应用程序的速度。
  • @Yakk 实际上,这个问题是this one 的后续问题。如果您能对这个问题发表评论/回答会很好,因为这里的这个问题实际上只是关于比较器。
  • @tobi303 正如我在那里提到的,使用排序向量来查找最低的 100 个项目也是一个坏主意。它是O( m n lg n ),其中m 是总元素,n 是极限。您可以在O( m lg n ) 中进行操作。

标签: c++ compare


【解决方案1】:

没有标准的函数模板来做你想做的事;但是有一个标准函数 class 模板,std::less。如果您要使用通用函数对象,而不是将自己限制为函数指针,那么很容易将其指定为默认值:

template <typename T, typename Comparator = std::less<T> > 
class SortedVector{
public:    
    SortedVector(Comparator comparator = Comparator()){
        this->comparator = comparator;
    }
    void insertValue(T newElement){
        // lower_bound accepts any suitable function object, so no change needed
        vect.insert(std::lower_bound(
           vect.begin(),vect.end(),newElement,comparator),newElement);
    }
private:
    std::vector<T> vect;
    Comparator comparator;
};

【讨论】:

  • 注意:std::less 自 C++11 起可用。
  • @juanchopanza 我也这么认为,但它是not 所以...
  • @black:没有默认参数的版本被标记为“直到 C++14”。它在 C++98 和之前的 STL 中可用。现在它已被替换为(向后兼容)版本,如果您不指定参数类型,该版本会推断出参数类型,并且如果您指定它们,则其行为与以前完全相同。
  • 一段时间后,我再次处理这个问题,现在我想知道是否真的有必要将 Comparator 类型作为模板参数,无论如何它将是 bool (*Comparator)(const T&amp;,const T&amp;) 和实际实例被传递给构造函数。是否可以将其作为 typedef 添加到类中并跳过模板参数? (我试过了,但是编译器在构造函数参数列表中抱怨Comparator comparator = std::less&lt;T&gt; 中的T。)
  • @tobi303:一般来说使用std::less之类的函数类比使用函数指针要好,这样函数调用是直接且可内联的。如果您出于某种原因特别不喜欢模板,则可以将类型硬编码为函数指针;但性能可能会受到影响,您需要为默认比较器提供一个函数,而不是 std::less
【解决方案2】:

您可以默认使用类模板std::less&lt;T&gt;

template <typename T, typename C=std::less<T>>
class SortedVector
{
public:    
  SortedVector(C cmp=C()) : comparator(cmp)
  {
  }
  void insertValue(T newElement){            
    vect.insert(std::lower_bound(
       vect.begin(),vect.end(),newElement,comparator),newElement);
}
private:
    std::vector<T> vect;
    C comparator;
};

【讨论】:

    猜你喜欢
    • 2021-11-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多