【问题标题】:Why is std::max not working for string literals?为什么 std::max 不适用于字符串文字?
【发布时间】:2021-11-06 16:44:35
【问题描述】:

我试图找到两个字符串的最大值,它在第一种情况下给出了正确的答案(传递std::string 变量时),但在第二种情况下给出了错误(传递直接字符串时)。

#include<bits/stdc++.h>
using namespace std;

int main()
{
    // Case 1
    string str1 = "abc", str2 = "abcd";
    cout << max(str1, str2) << endl;

    // Case 2
    cout << max("abc", "abcd") << endl;
}

【问题讨论】:

标签: c++ algorithm max stdstring c++-standard-library


【解决方案1】:

在第二种情况下,

std::cout << std::max("abc", "abcd") << std::endl;

它们是字符串文字,其中"abc" 的类型为char const [4],"abcd" 的类型为char const [5]。

因此,在函数调用std::max("abc", "abcd")中,std::max不得不推导出来

auto max(char const (&a)[4], char const (&b)[5]) {
    return a < b ? b : a;
}

这是不可能的,因为std::max 没有函数模板重载,它采用不同的类型作为模板参数。因此,错误!


警告!

如果您在std::max 中明确提及模板类型const char*,则可能已编译。这是因为,对于 "abc" 和 "abcd",由于 C++ 中数组到指针的衰减,类型也可以是 const char*s。

 std::cout << std::max<const char*>("abc", "abcd" ) << '\n';  // compiles
                      ^^^^^^^^^^^^^

另外,std::max 的std::initializer_list 重载,反过来也会将上面的const char* 推导出为模板类型:

std::cout << std::max({ "abc", "abcd" }) << '\n';   // compiles

但是,你不应该这样做!

正如@AlanBirtles 指出的那样,这可能会导致undefined behavior,因为std::max 将比较两个不同数组的指针。结果不能被转发,应该做上面的事情。与第一种情况一样,使用std::string 进行比较。使用string literals(C++14 起),你可以做一个最小的改变,使第二种情况与第一种情况相同:

#include <string>
using namespace std::string_literals;

std::cout << std::max("abc"s, "abcd"s) << '\n';

附带说明,请参阅以下内容:

【讨论】:

  • 虽然 const char* 变体可能会编译比较来自两个单独数组的指针具有未定义的行为,但它也可能只返回内存中第二次存储的任何文字,这不太可能是 OP 想要的并且肯定与std::strings 的行为不同
  • 例如这个输出可能令人惊讶:godbolt.org/z/6E1odqT4a
【解决方案2】:

区别来自于类型。

典型的 max 实现可能如下所示:

template <typename T>
auto max(const T &a, const T &b) {
    return a < b ? b : a;       
}

当您将 max 用于 std::string 时,&lt; 符号实际上已超载。 std::string::operator&lt;() 方法用于比较字符串。

当您将 max 用于 const char * 时。 &lt; 只是比较指针而不考虑字符串的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 2019-03-06
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多