STD :: String应该专门使用STD ::支持异质查找的支持吗?

发布于 2025-02-04 06:14:07 字数 1370 浏览 3 评论 0 原文

能够在带有的容器中查找 char*,而无需创建临时字符串对象,而无需创建 ://www.cppstories.com/2021/heterogeneous-access-cpp20/“ rel =“ nofollow noreferrer”>好东西。请参阅:避免使用std :: map :: find() https://www.cppstories.com/2021/2021/heterogeneous-eterogenous-access-access-access-cpppps-cpp20/ 和...

有原因为什么C ++为什么无法为任何类型的 t 用作关键类型的任何类型启用。

因此,与C ++ 20/23起,我们将剩下:

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&lt; std :: string&gt; 提供(部分?)专业?是否尚未指定这一点,或者是否有任何合法原因为什么 std :: string (或者 std :: basic_string&lt; ...&gt; )无法执行此操作?

Being able to look up a char* in a container with find without needing to create a temporary string object is a Good Thing. See: Avoiding key construction for std::map::find() and https://www.cppstories.com/2021/heterogeneous-access-cpp20/ and ...

There are reasons why C++ could not enable this for any type T used as a key type.

So, as of C++20/23 we are AFAIKT left with:

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");
    }
}

However - I was wondering why std::string doesn't automatically opt-in to this by providing a (partial?) specialization for std::less<std::string>? Has this simply not been specified yet, or are there any legitimate reasons why std::string (or rather std::basic_string<...>) cannot do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自由如风 2025-02-11 06:14:07

我认为主要原因是没有人提出它。魔术没有任何事情发生,必须由某人提出,然后审查和批准。如果提案步骤没有发生,什么都不会改变。

但是,应该注意的是,制作 std :: Less&lt; std :: string&gt; 透明是对类型的打破变化,例如:

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 :::字符串或首先转换为 std :: String 然后进行比较。

今天,将此类的实例传递到 map&lt; string,int&gt; :: find(const string&amp;)将隐式转换为 std :: String ,因此请使用 m_str1 。但是,如果 std :: Less&lt; std :: string&gt; 是透明的,则将使用 m_str2 进行比较。那会改变行为。

可以说,这堂课很愚蠢,值得打破。由于添加&lt; =&gt; 语言对与这种奇怪行为的比较不一致的比较要少得多。但是,即使乍看之下,即使破裂的代码看起来愚蠢,也总是需要仔细考虑打破变化。

可以制作 std :: Less&lt; std :: string&gt; 能够直接与 Just const char*进行比较std :: string_view 没有转换(对于操作员&lt; ),例如

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 string_view )的类型/code>)现在将无法传递给 std :: Less&lt; std :: string&gt; ,因为它会变得模棱两可。这可以解决,例如

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 ),容器不会定义采用任意密钥的其他功能模板。因此,额外的 sill&lt; string&gt; :: operator() Overloads将不会使用,并且您仍然会转换为 std :: String 查找(“ OLAF”)

对不起。

I think the primary reason is that nobody proposed it. Nothing happens by magic, it has to be proposed by somebody and then reviewed and approved. If the proposal step doesn't happen, nothing will change.

However, it should be noted that making std::less<std::string> transparent would be a breaking change for types like:

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; }
};

This class behaves differently when compared directly to a std::string or when converted to std::string first and then compared.

Today, passing an instance of this class to map<string, int>::find(const string&) would implicitly convert to std::string and so use m_str1. But if std::less<std::string> was transparent, it would compare using m_str2. That would change behaviour.

Arguably, this class is stupid and deserves to break. Since the addition of <=> the language is much less forgiving of inconsistent comparisons with this kind of odd behaviour. But breaking changes always need to be considered carefully, even if the code that would break looks stupid at first glance.

It would be possible to make std::less<std::string> able to compare directly to just const char* and std::string_view without conversions (which is already true for operator<), e.g.

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;
};

But this could also be a breaking change. A type that is convertible to std::string and const char* (or std::string and std::string_view) would now be unable to be passed to std::less<std::string> because it would become ambiguous. That can be solved, e.g.

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;
};

But this wouldn't actually help. Because this specialization doesn't define the is_transparent member (because it's not fully transparent, because it only accepts three types, not anything comparable with std::string), the associative containers would not define the additional function templates that take an arbitrary key. And so the extra less<string>::operator() overloads wouldn't be used, and you'd still get a conversion to std::string when you do find("Olaf").

Sorry.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文