8

假设我有一个字符串向量,我想找到所有以 开头的字符串,'a'所以我可以这样做:

struct cmp {
    bool operator()( const std::string &s, char c ) const { return s.front() < c; }
    bool operator()( char c, const std::string &s ) const { return s.front() < c; }
};
std::vector<std::string> strings;
...
std::sort( strings.begin(), strings.end() );
auto range = std::equal_range( strings.begin(), strings.end(), 'a', cmp{} );
...

这种方法容易出错,因为容易出错(例如我认为它应该c < s.front()在第二种方法中)并且有代码重复。

那么是否可以使用通用 lambda 而不是使用 2 种方法的结构来实现比较功能?

更一般的问题,为什么要比较的值必须作为参数传递给std::lower_boundstd::upper_bound什么std::equal_range时候它可以很容易地被 lambda 捕获或传递给比较结构,那么这个问题就根本不存在了?

std::equal_range如果不需要价值,它如何工作?

struct cmp {
    cmp( char lc ) : c( lc ) {}
    bool operator()( const std::string &s ) const { return s.front() < c; }
    char c;
};
std::vector<std::string> strings;
...
std::sort( strings.begin(), strings.end() );
auto range = std::equal_range( strings.begin(), strings.end(), cmp{'a'} );
4

2 回答 2

5

lower_bound

std::partition_point(strings.begin(), strings.end(),
                     [](const auto& s) { return s.front() < 'a'; });

upper_bound

std::partition_point(strings.begin(), strings.end(),
                     [](const auto& s) { return s.front() <= 'a'; });

是的,这意味着您必须编写两个调用才能获得等效的equal_range. 你可以把它包装成一个免费的模板:

template<class Iter, class T, class Proj>
std::pair<Iter, Iter> my_equal_range(Iter first, Iter last, const T& value, Proj proj) {
    auto b = std::partition_point(first, last, [&](const auto& s) { return proj(s) < value; });
    auto e = std::partition_point(b, last, [&](const auto& s) { return !(value < proj(s)); });
    return {b, e};
}

并将其称为

my_equal_range(strings.begin(), strings.end(), 'a',
               [](const auto& s) { return s.front(); });

Ranges TS 工作草案向算法添加了预测,因此您将(最终)能够做到这一点:

std::experimental::ranges::equal_range(strings, 'a', {},
                                       [](const auto& s) { return s.front(); });
于 2015-10-30T14:22:08.010 回答
4

要回答您的第一个问题,是否可以使用通用 lambda 实现比较器,是的,可以。您还需要几个辅助函数来返回给定charstring参数的所需结果。

auto get_char(char c)               { return c; }
auto get_char(std::string const& s) { return s.front(); }
auto cmp = [](auto const& l, auto const& r) { return get_char(l) < get_char(r); };

现场演示


您不能简单地让比较器捕获该值的一个原因是因为 的两个重载equal_range可能是模棱两可的,您需要稍微不同的名称或其他方式(例如,标签参数)来消除两者的歧义。

于 2015-10-30T06:50:31.103 回答