英文:
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::strings (or better, std::string_views), 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::strings (or better, std::string_views), 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::strings before comparing, and the comparison between two std::strings 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论