有没有办法使用 std::less<> 的转发和自定义比较同时与 std::set/std::map 进行比较?



如果我声明std::set<std::string>我会得到区分大小写的比较。 如果我想要不区分大小写,我可以编写自己的比较并像std::set<std::string,cmpi>一样声明,这也很好用。

struct cmpi { 
bool operator() (const std::string& a, const std::string& b) const {
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};

但是,在高使用率的情况下,我使用const char *搜索std::set,例如find("string")find(pszVar),不幸的是,为比较操作创建了一个临时std::string(strlen,alloc,free)。 我可以通过使用std::set<std::string,std::less<>>来避免所有这些,它按原样转发类型,没有临时的,并且可以很好地进行区分大小写的比较。 但是,不区分大小写的比较版本呢?

在此示例中,我将创建一个类来确保事情按预期发生:

#include <iostream>
#include <set>
#include <string>
#include <string.h>

class Str : public std::string {
public:
Str(const char *s) : std::string(s) {
std::cout << "create" << std::endl;
}
~Str() {
std::cout << "destroy" << std::endl;
}
bool operator<(const Str &s) const {
std::cout << "local comparing Str:" << *this << " to Str:" << s << std::endl;
return strcasecmp( c_str(), s.c_str() ) < 0;
}
bool operator<(const char *s) const {
std::cout << "local comparing Str:" << *this << " to char*:" << s << std::endl;
return strcasecmp( c_str(), s ) < 0;
}
};

int main(void) {
std::set<Str,std::less<>> list;
list.emplace("A");
list.emplace("D");
list.emplace("C");
list.emplace("b");
for ( const auto &s : list ) {
std::cout << s << std::endl;
}
if ( auto s = list.find("c"); s != list.end() ) {
std::cout << "found c!" << std::endl;
}
else {
std::cout << "c not found" << std::endl;
}
return 0;
}

4 为置换创建,输出顺序AbCD,并且没有临时创建以成功查找。

那么,有没有办法两全其美,而不必声明两种对象类型......同时转发比较类型的自定义比较? 我尝试了一些变体,例如围绕模板化的 std::less 的命名空间,围绕运算符的命名结构,所以我可以有两个集合,等等,但没有成功。

重申一下:我不想要一种或另一种比较类型...我想同时拥有:

std::set<Str,std::less<>> list_no_case;
std::set<Str,????> list_case;

>我可以通过使用std::set<std::string,std::less<>>来避免所有这些

不,您可以通过使用执行非对称比较的比较函数来避免所有这些,std::less<>就是一个例子(它之所以有效,std::string具有char const*<比较运算符)。你可以用cmpi写自己的.只需添加额外的operator()重载即可在std::stringchar const*之间进行比较。

using is_transparent = int;
bool operator() (const std::string& a, const std::string& b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
bool operator() (char const *a, const std::string& b) const
{
return strcasecmp(a, b.c_str()) < 0;
}
bool operator() (const std::string& a, char const *b) const
{
return strcasecmp(a.c_str(), b) < 0;
}

请注意,需要using is_transparent部分才能完成此操作。这是比较用来向容器发出信号,表明它允许非对称比较。

最新更新