【问题标题】:STL and std custom compare arguments working in c++在 C++ 中工作的 STL 和 std 自定义比较参数
【发布时间】:2021-08-31 03:50:18
【问题描述】:

我在stackoverflow上问了这个问题STL passing object

我知道我们传递的对象在 tern 中调用比较运算符并比较我们的值并给我们一个结果。都很好。

现在在这段代码中:

class Compare {
    public:
    bool operator ()(const int &a, const int &b) { return a < b;}
};

void solve(){
    set<int, Compare> s;
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}

如果我执行 Compare() 会出错,这是我认为必须完成的(传递对象)。为什么这样?我们如何通过比较?

同样在这段代码中,我无法传递如下函数:

bool comp(const int &a, const int &b) { return a < b; }

void solve(){
    set<int, comp> s;
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}

这是我所期望的。不传递函数。

现在在这段代码中:

bool comp(const int &a, const int &b) { return a < b; }

void solve(){
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    nth_element(arr.begin(), arr.begin()+3, arr.end(), comp);
    for(int e : arr) cout << e << " "; cout << endl;
}

我能够传递一个函数并且没有错误。我的意思是发生了什么事?从我的角度来看,我们应该只传递对象,它们会调用它们的 () 重载运算符并比较值,但有时我们传递函数,有时传递对象会出错,​​有时我们只传递类名。 c++到底发生了什么

【问题讨论】:

  • 能否提供每种情况的错误信息?
  • 很多错误,比如函数返回函数。没有已知的参数 2 从“比较”到“布尔”的转换。等等,但基本上说我无法比较我的做法
  • STL 是一个库,它是 c++ 标准库的前身。您的标题表明您正在谈论 STL 和标准库,但我认为您的意思是标准库

标签: c++ templates stl set function-object


【解决方案1】:

std::set 的第二个模板参数是一个类型。

你可以使用函数指针:

bool comp(const int &a, const int &b) { return a < b; }

std::set<int, bool (*)(const int &, const int &)> s(comp);

【讨论】:

    【解决方案2】:

    在第一个代码 sn-p 中,编译器发出错误,因为您使用对象 Compare() 作为类型模板参数而不是类型 Compare。

    如果你会写例如

    #include <iostream>
    #include <vector>
    #include <set>
    
    using namespace std;
    
    class Compare {
        public:
        bool operator ()(const int &a, const int &b) const { return a < b;}
    };
    
    int main() 
    {
        set<int, Compare> s( ( Compare() ) );
        
        vector<int> arr = {1,4,6,3,7,2,8,588,5};    
        for(int e : arr) s.insert(e);
        for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;   
    
        return 0;
    }
    

    则程序编译成功,输出为

    588 8 7 6 5 4 3 2 1 
    

    即作为类模板std::set 的第二个类型模板参数,您需要使用类型说明符比较。但是如果要指定构造函数的参数,则需要使用模板参数类型的对象。

    第二个代码sn-p也存在同样的问题。您需要像此演示程序中所示那样编写。

    #include <iostream>
    #include <vector>
    #include <set>
    
    using namespace std;
    
    bool comp(const int &a, const int &b) { return a < b; }
    
    int main() 
    {
        set<int, bool ( * )( const int &, const int & )> s( comp );
        
        vector<int> arr = {1,4,6,3,7,2,8,588,5};    
        for(int e : arr) s.insert(e);
        for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;   return 0;
    }
    

    程序输出同上图。

    注意类模板 std::set 的声明如下

    template <class Key, class Compare = less<Key>, 
              class Allocator = allocator<Key> >
    class set;
    

    因此,如果您明确指定了第二个模板参数(而不是默认使用函数对象std::less&lt;Key>),那么您需要在类模板 std::set 的构造函数中提供此类型的相应对象。

    【讨论】:

    • 第一个是正确的。但是如果我通过 Compare() 而不是 Compare 我会得到一个错误
    • @ShobhitTewari:Compare 是一个(类)类型。 Compare( ) 是Compare 类型的临时对象,通过调用默认构造函数Compare::Compare( ) 创建。这个 ctor 什么都不做,由编译器为你隐式定义。
    • @ShobhitTewari 模板参数指定类型模板参数。构造函数 std::set 的参数是类型模板参数的对象。
    • @MSalters Compare() 也可以是一个类型(一个不带参数的函数类型,返回Compare)。目前尚不清楚 OP 是如何使用它的。
    • @AyxanHaqverdili:OP 字面意思是 class Compare { ...
    【解决方案3】:

    operator() 必须是常量。这就是 API。

    class Compare {
        public:
        bool operator ()(const int &a, const int &b) const { return a < b; }
    }
    

    【讨论】:

    • 即使不是 const 也不会报错。如果我做比较()而不是比较,它会给我设置错误。还有分号,我说 for 循环范围到此结束,我正在写一个新行。我只是这样做,因为我专注于学习。
    • @ShobhitTewari 你如何使用Compare()?你不能这样做set&lt;int, Compare()&gt;,那行不通
    • 所以在set类中是这样的,我传递的任何类型都会创建对象然后调用重载函数?如果是的话,我明白了。在某个地方设置类比较 c; c(a, b)
    • @ShobhitTewari:您可能想要一本好的 C++ 书籍。 std::set 是一个类模板。它使用 值类型 和可选的提供设置顺序的比较类型进行实例化。那是两种类型。一些模板接受非类型模板参数,但 `std::set` 只接受类型。
    • 是的,我明白了。谢谢。现在很清楚了。问题是接受哪个答案,因为所有答案都是正确的。
    猜你喜欢
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多