能够在具有char*
的容器中查找find
而不需要创建临时字符串对象,这是一个好东西。见:避免std::map::find()的关键构造和https://www.cppstories.com/2021/heterogeneous-access-cpp20/还有..。
有理由为什么C++不能为用作键类型的任何类型T
启用此功能。
因此,在C++20/23中,我们是AFAIKT,剩下:
int main()
{
{
// Slow, constructs temporary
std::map<std_string, int> m;
auto it = m.find("Olaf");
}
{
// "Fast" does not need to construct temporary
std::map<std_string, int, std::less<>> m;
auto it = m.find("Olaf");
}
}
然而,-我想知道为什么std::string
不自动选择-通过提供一个(部分?)专门化的std::less<std::string>
?std::string
(或者更确切地说是std::basic_string<...>
)不能这么做是有什么正当理由的吗?
发布于 2022-06-08 10:43:35
我认为最主要的原因是没有人提出。没有什么是魔术发生的,它必须有人提出,然后审查和批准。如果提议的步骤没有发生,什么也不会改变。
但是,应该注意的是,使std::less<std::string>
透明对于以下类型来说将是一个巨大的改变:
class StupidString
{
std::string m_str1;
std::string m_str2;
public:
// Constructors etc. ...
operator std::string() const { return m_str1; }
std::strong_ordering operator<=>(const std::string& s) const
{ return m_str2 <=> s; }
};
如果直接与std::string
相比,或者先转换为std::string
,然后再进行比较,该类的行为会有所不同。
今天,将该类的一个实例传递给map<string, int>::find(const string&)
将隐式转换为std::string
,因此使用m_str1
。但是如果std::less<std::string>
是透明的,它将使用m_str2
进行比较。这将改变行为。
可以说,这门课是愚蠢的,理应停课。自从添加了<=>
之后,语言就更不宽容与这种奇怪行为进行不一致的比较。但是,打破的变化总是需要仔细考虑,即使代码,将打破乍一看看起来很愚蠢。
可以使std::less<std::string>
能够直接与const char*
和std::string_view
进行比较,而不需要转换(对于operator<
来说已经是如此)。
template<>
struct less<string>
{
bool operator()(const string&, const string&) const noexcept;
// Not in the standard today:
bool operator()(const string&, string_view) const noexcept;
bool operator()(const string&, const char*) const noexcept;
bool operator()(string_view, const string&) const noexcept;
bool operator()(const char*, const string&) const noexcept;
};
但这也可能是一个巨大的变化。可转换为std::string
和const char*
(或std::string
和std::string_view
)的类型现在将无法传递给std::less<std::string>
,因为它将变得不明确。这是可以解决的。
template<typename T>
concept string_view_or_char_ptr
= same_as<string_view> || same_as<T, const char*> || same_as<T, char*>;
template<>
struct less<string>
{
bool operator()(const string&, const string&) const noexcept;
// Not in the standard today:
template<string_view_or_char_ptr T>
bool operator()(const string&, T) const noexcept;
template<string_view_or_char_ptr T>
bool operator()(T, const string&) const noexcept;
};
但这根本帮不上忙。因为这种专门化没有定义is_transparent
成员(因为它不完全透明,因为它只接受三种类型,而不是任何类似于std::string
的类型),所以关联容器不会定义接受任意键的附加函数模板。因此,额外的less<string>::operator()
重载不会被使用,并且在执行find("Olaf")
时仍然会得到到std::string
的转换。
抱歉的。
https://stackoverflow.com/questions/72476043
复制相似问题