英文:
Why sorting a vector of strings with generic lambda doesn't work?
问题
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool sortByName(const auto& first, const auto& second) {
return first < second;
}
void print(const auto& vec) {
for(const auto& s : vec)
cout << s << ", ";
cout << endl;
}
int main() {
vector<string> vec2 = {"sam", "zach", "adam", "peter"};
print(vec2);
auto cmp = [](const auto& s1, const auto& s2) {
return s1 < s2;
};
std::sort(vec2.begin(), vec2.end(), cmp); // line (1)
print(vec2);
auto cmp2 = [](const string& s1, const string& s2) {
return s1 < s2;
};
std::sort(vec2.begin(), vec2.end(), cmp2); // line (2)
print(vec2);
}
关于为什么在 cmp2
中需要显式提供类型 "string" 以使排序工作的问题,是因为C++中的lambda表达式(匿名函数)需要知道参数的类型。在 cmp
中,使用了 "const auto&",这意味着编译器会根据传入的参数类型来确定参数类型。但在 cmp2
中,使用了 "const string&",这里明确指定了参数类型为 "string",因此编译器知道应该处理字符串类型的参数。如果不指定类型,编译器将无法确定参数的类型,从而无法正确地比较字符串并进行排序。
英文:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool sortByName(const auto& first, const auto& second) {
return first < second;
}
void print(const auto& vec) {
for(const auto& s : vec)
cout << s << ", ";
cout << endl;
}
int main() {
vector vec2 = {"sam", "zach", "adam", "peter"};
print(vec2);
auto cmp = [](const auto& s1, const auto& s2) {
return s1 < s2;
};
std::sort(vec2.begin(), vec2.end(), cmp); // line (1)
print(vec2);
auto cmp2 = [](const string& s1, const string& s2) {
return s1 < s2;
};
std::sort(vec2.begin(), vec2.end(), cmp2); // line (2)
print(vec2);
}
For the above code snippet, the results are as below,
- std::sort with cmp2 sorts the vector i.e. {adam, peter, sam, zach,}
- std::sort with cmp keeps the elements of vector in same order, as the original vector i.e. {sam, zach, adam, peter,}
Why do we have to explicitly provide the type i.e. "string" in cmp2 to make this sort work?
答案1
得分: 2
vector vec2 = {"sam", "zach", "adam", "peter"};
This makes vec2
into a std::vector<const char*>
.
You are therefore comparing const char*
in the generic lambda and not what the pointers are actually pointing at.
In order to make it work without converting the const char*
s to std::string
s (or better, std::string_view
s), you could use std::strcmp
:
#include
auto cmp = [](const char* s1, const char* s2) {
return std::strcmp(s1, s2) < 0;
};
英文:
vector vec2 = {"sam", "zach", "adam", "peter"};
This makes vec2
into a std::vector<const char*>
.
You are therefore comparing const char*
in the generic lambda and not what the pointers are actually pointing at.
In order to make it work without converting the const char*
s to std::string
s (or better, std::string_view
s), you could use std::strcmp
:
#include <cstring>
auto cmp = [](const char* s1, const char* s2) {
return std::strcmp(s1, s2) < 0;
};
答案2
得分: 2
因为在这行代码中 vector vec2 = {"sam", "zach", "adam", "peter"}
,你没有指定向量元素的类型,而类型是从初始化程序中推断出来的。由于你使用了字符串字面值 (const char[]
),因此 vec2
的类型被推断为 std::vector<const char*>
而不是 std::vector<std::string>
。
然后,在你定义 auto cmp = [](const auto& s1, const auto& s2)
时,你再次要求编译器推断 s1 和 s2 的类型。通过在 std::sort
中使用 lambda 表达式,类型被推断为 std::vector<const char*>
的 value_type
,因此你实际上正在比较两个 const char*
,这是指针比较,比较不相关的指针是未定义行为,意味着可以发生任何事情。
当你使用形式 [](const std::string& s1, const std::string& s2)
时,向量中存储的 const char*
被转换为临时的 std::string
,然后进行比较,两个 std::string
之间的比较是定义良好的,可以得到预期的结果。
顺便提一下,不要使用 using namespace std
,特别是如果你刚开始学习 C++。(https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice)
英文:
That is because in the line vector vec2 = {"sam", "zach", "adam", "peter"}
, you didn't specify the type of the element of the vector, and the type is deduced from the initializer. Since you used string literals (const char[]
), the type of vec2
is deduced to be std::vector<const char*>
instead of std::vector<std::string>
.
Then later when you define auto cmp = [](const auto& s1, const auto& s2)
, you are asking the compiler to deduce the types of s1 and s2 again. By using the lambda in std::sort
, the type is deduced to the value_type
of std::vector<const char*>
, so you are really comparing two const char*
, which are pointer comparisons and comparison of unrelated pointers are undefined behavior, meaning anything can happen.
When you use the form [](const std::string& s1, const std::string& s2)
, the const char*
stored in the vector are converted to temporary std::string
s before comparing, and the comparison between two std::string
s are well-defined, giving the expected result.
As a side note, do not use using namespace std
especially if you are just starting to learn C++.(https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论