自C++14起,是否总是更喜欢使用set<T, less<>> 而不是 set<T>?

30
#include <set>
#include <string>
#include <string_view>

using namespace std;

int main()
{
    string_view key = "hello";

    set<string> coll1;
    coll1.find(key); // error

    set<string, less<>> coll2;
    coll2.find(key); // ok since C++14
}

那么,应该制定一个规则吗:
自C++14以来,始终优先选择set<T, less<>>而不是set<T>

1
你是否正在使用透明比较器功能?如果没有,那么为什么要费心呢? - ildjarn
@ildjarn:什么是“透明比较器功能”? - Nicol Bolas
1
@NicolBolas :除了拼写错误之外,这是 less<>less<T> 之间的区别 - ildjarn
@ildjarn:哦,这就是为什么谷歌让我失望了。那就算了吧。 - Nicol Bolas
string_view 不在 C++14 中。 - M.M
2个回答

19

找到反例非常简单:

#include <set>
#include <string>

using namespace std;

struct converts_to_string {
    operator string() const { return ""; }
};

int main()
{
    converts_to_string key;

    set<string> coll1;
    coll1.find(key); // OK

    set<string, less<>> coll2;
    coll2.find(key); // error
}

2
它为什么不能运行呢?是因为标准不要求(禁止?)在basic_string上定义的operator<必须是非成员函数,因此推导失败了吗?如果将basic_stringoperator<定义为友元(非模板)函数,那么它会工作吗? - dyp
2
@dyp 是的,推断失败是因为它是一个非成员函数模板(与 basic_string_view 不同,它没有“足够的附加重载”规则)。是的,友元非模板函数可以使这个工作(代价是每次比较一个临时字符串,就像你的 stupid_string 一样)。 - T.C.

10

当使用associative_container<T, less<>>时,可能会存在性能下降的情况:考虑一个类型如下:

#include <iostream>
#include <set>
#include <string>

struct stupid_string
{
    stupid_string(char const* s)
      : s(s)
    { std::cout << "copy\n"; }

    stupid_string(char const* s, int) // silent
      : s(s)
    {}

    friend bool operator<(stupid_string const& lhs, stupid_string const& rhs);

private:
    std::string s;
};

bool operator<(stupid_string const& lhs, stupid_string const& rhs) {
    return lhs.s < rhs.s;
}

int main() {
    std::set<stupid_string, std::less<>> s;
    s.emplace("hello", 0);
    s.emplace("world", 0);
    s.emplace("foobar", 0);
    std::cout << "find\n";
    (void)s.find("test");
}

在这里,s.find 算法中使用的 operator< 将字符面量隐式转换为 stupid_string。每次比较都会发生这种情况! 在线演示 我知道一个类似的事情在生产代码中出现过,是由于非符合 C++03 StdLib 实现引起的。
顺便说一下,这也是异构查询通过 less<> 变成可选择的主要原因;请参见 N3657

Stephan T. Lavavej 建议容器检测比较对象是否接受异构参数,并有条件地重载当前查找函数的模板版本,这样就可以解决保留现有行为和允许异构查找两个问题。


2
这基本上是异构查找被设置为选择加入的原因。 - T.C.
@T.C. 是的,但我找不到引用。 - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接