简体   繁体   English

是否可以将std :: sort与带有额外参数的sort函数一起使用?

[英]Is it possible to use std::sort with a sort function that takes extra arguments?

This is something that I've been considering for a while. 这是我一直在考虑的事情。 I've done some research and can't find anything on it, but I haven't found anything to the contrary either. 我已经做了一些研究而且找不到任何东西,但我也没有发现任何相反的东西。

Consider the std::sort function in <algorithm> . 考虑<algorithm>std::sort函数。 It takes two iterators and a function pointer as arguments. 它需要两个迭代器和一个函数指针作为参数。 So if I wanted to sort a vector of strings alphabetically, I would do something like this: 所以,如果我想按字母顺序对字符串向量进行排序,我会这样做:

bool ascending(std::string lhs, std::string rhs) { return lhs < rhs; }

std::sort(my_vector.begin(), my_vector.end(), ascending);

The thing is that this type of sort function is case-sensitive, so would place a string beginning with lowercase 'a' after strings beginning with uppercase 'Z'. 问题是这种类型的sort函数区分大小写,因此在以大写“Z”开头的字符串后面会放置以小写“a”开头的字符串。 The only visible solution I see to this is creating an additional function along the lines of bool ascending_case_insensitive() . 我看到的唯一可见解决方案是沿着bool ascending_case_insensitive()创建一个额外的函数。 However, it would be nice if I could have a function bool ascending() with an additional bool is_case_sensitive parameter to use in sort. 但是,如果我可以使用函数bool ascending()并在sort中使用另外的bool is_case_sensitive参数,那将是很好的。 Is this possible? 这可能吗?

Where you now have 你现在的位置

bool ascending(std::string lhs, std::string rhs);

std::sort(my_vector.begin(), my_vector.end(), ascending);

you can have 你可以有

bool ascending(std::string lhs, std::string rhs, bool case_sensitive);

using namespace std::placeholders;
std::sort(my_vector.begin(), my_vector.end(), std::bind(ascending, _1, _2, false));

The point of std::bind is to return an object that when invoked, calls the bound function, optionally with altered arguments. std::bind的目的是返回一个对象,该对象在调用时调用绑定函数,可选地使用更改的参数。 You can use it to change argument order, add optional parameters, or set parameters to specific fixed values. 您可以使用它来更改参数顺序,添加可选参数或将参数设置为特定的固定值。

Since std::sort takes an instance of the comparison functor, you can use arguments to your functor's constructor determine its behaviour. 由于std :: sort采用了比较仿函数的一个实例,因此您可以使用仿函数构造函数的参数来确定其行为。 For example, 例如,

class StringCompare
{
public:
StringCompare(bool is_case_sensitive=true) : is_case_sensitive(is_case_sensitive){}
bool operator()(const string&, const string&);///This would handle the comparison using the is_case_sensitive flag
private:
bool is_case_sensitive;
};

std::sort(my_vector.begin(), my_vector.end(), StringCompare(true));//case-sensitive comparison
std::sort(my_vector.begin(), my_vector.end(), StringCompare(false));//case-insensitive comparison

There follows an example that includes a function call with a bound extra parameter and a lambda expression that captures the extra parameter by value: 下面是一个示例,其中包含带有绑定额外参数的函数调用和通过值捕获额外参数的lambda表达式:

#include <iostream>// for std::cout
#include <vector>// for std::vector
#include <functional> // for std::bind
#include <algorithm> // for std::sort

bool ltMod(int i, int j, int iMod) {
    return (i % iMod) < (j % iMod); 
}

int main() {
    std::vector<int> v = {3,2,5,1,4};
    int iMod = 4;

    std::cout << "\nExample for the usage of std::bind: ";
    // _1 and _2 stand for the two arguments of the relation iMod is the bound parameter
    std::sort(v.begin(),v.end(),std::bind(ltMod,std::placeholders::_1,std::placeholders::_2,iMod));

    for( auto i : v )   std::cout << i << ',';

    iMod = 3;

    std::cout << "\nExample for lambda: ";
    // lambdas are unnamed inplace functions
    // iMod is captured by value. You can use the value within the function.
    std::sort(v.begin(),v.end(),[iMod](int i, int j){ return ltMod(i,j,iMod); });
    for( auto i : v )   std::cout << i << ',';

    return 0;
}
/**
     Local Variables:
     compile-command: "g++ -std=c++11 test.cc -o a.exe"
     End:
*/

Thought that I would answer my own question in order to summarize the responses I've gotten. 以为我会回答我自己的问题,以便总结我得到的答案。 So from what I gather, I basically have two options. 所以从我收集的内容来看,我基本上有两种选择。

The first would be to write a lambda function to handle my one-time case. 第一个是写一个lambda函数来处理我的一次性案例。

// Lambda solution.
std::sort(my_vector.begin(), my_vector.end(),
    [](std::string const &lhs, std::string const &rhs)    // Thanks for optimizing my example code guys. No, seriously. ;)
    {
        return boost::toupper(lhs) < boost::toupper(rhs);
    });

The second, more reusable option would be to create a functor to handle sort situations like these. 第二个更可重用的选项是创建一个仿函数来处理这样的排序情况。

// Functor solution.
class SortAscending
{
private:
    bool _is_case_sensitive;
public:
    SortAscending(bool is_case_sensitive) :
        _is_case_sensitive(is_case_sensitive);

    bool operator()(std::string const &lhs, std::string const &rhs)
    {
        if (_is_case_sensitive)
            return boost::toupper(lhs) < boost::toupper(rhs);
        else
            return lhs < rhs;
    }
};

std::sort(my_vector.begin(), my_vector.end(), SortAscending(false));

So think that pretty much sums up my options? 所以认为这几乎总结了我的选择?

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

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