2
#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,

  1. std::sort with cmp2 sorts the vector i.e. {adam, peter, sam, zach,}
  2. 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?

2 Answers2

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 <cstring>

auto cmp = [](const char* s1, const char* s2) {
    return std::strcmp(s1, s2) < 0;
};
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
2

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++.(Why is "using namespace std;" considered bad practice?)

Weijun Zhou
  • 746
  • 1
  • 7
  • 25
  • 1
    Thank you for your answer. I don't have enough reputations to cast a vote. Bdw, I don't use std namespace directly in my code but as it was a sample code for stack overflow I used it that way. – SandeshK3112 Jul 10 '23 at 10:18
  • 1
    @SandeshK3112 No worries. I put my vote on this answer for you :-) – Ted Lyngmo Jul 10 '23 at 10:27