Pikachu
Pikachu

Reputation: 314

Unexpected output in string comparison

In the following CPP code, isGreater() function does its job right for integers. However, it does not produce the correct result for strings. My initial guess was that as std:: string ::compare() method has not been used so I created a specialized isGreater() template method for strings and first cout still produces output as 1. My thought is that it must compare strings alphabetically. But, I don't think so it's doing that. Second and third cout statements provide correct output i.e. integers in comparison and strings alphabetically. What exactly is going on in isGreater() for strings?

#include <iostream>
#include <string>
using namespace std;

template <typename T>
bool isGreater(T x1, T x2)
{
    return (x1 > x2);
}

template <>
bool isGreater(string x1, string x2)
{
    return (x1.compare(x2));
}

int main()
{
    cout << isGreater("AAAA", "ZZZZ") << endl; //First cout
    cout << isGreater(5, 10) << endl; //Second cout
    string str1 = "AAA";
    string str2 = "ZZZZZ";
    cout << str1.compare(str2) << endl; //Third cout
    return 0;
}

Upvotes: 1

Views: 111

Answers (3)

Some programmer dude
Some programmer dude

Reputation: 409176

The problem is that isGreater("AAAA", "ZZZZ") doesn't call your std::string specialization. It calls the general templated function using pointers (const char*), and you compare those pointers instead of the strings.

You need to add a specialization (or overload) taking the pointer arguments if you want to use literal strings.


As for the std::string specialization, the std::string::compare function doesn't return what you think it does.

It returns a "true" (non-zero) value if the strings are not equal, which could be negative (and as non-zero will be true) if x1 is smaller than x2. Either use the standard greater than operator (which is overloaded) or check if the returned value is greater than zero:

return x1.compare(x2) > 0;

Upvotes: 4

JVApen
JVApen

Reputation: 11317

As indicated in other answers, you don't call the std::string specialization, as you don't have a std::string, you have a const char [].

The best solution is to ensure that the templated method doesn't take over from the specialization. From C++17 on, I would use if constexpr, in C++11 and C++14, I would use std::enable_if. (Note that I use string_view to prevent memory allocations.)

template <typename T>
bool isGreater(T x1, T x2)
{
if constexpr (std::is_convertable_v<T, std::string_view>)
    std::string_view{x1}.compare(x2);
else
    return (x1 > x2);
}

Old standards:

template <typename T, typename = std::enable_if<!std::is_convertable<T, std::string>::value>::type>
bool isGreater(T x1, T x2)
{
    return (x1 > x2);
}

bool isGreater(string x1, string x2)
{
    return (x1.compare(x2));
}

Upvotes: 1

Nagappa
Nagappa

Reputation: 313

#include <iostream>
#include <string>
using namespace std;

template <typename T>
bool isGreater(T x1, T x2)
{
    return (x1 > x2);
}

bool isGreater(string x1, string x2)
{
    return (x1.compare(x2));
}

int main()
{
    cout << isGreater(string("AAAA"), string("ZZZZ")) << endl;
    cout << isGreater(5, 10) << endl;
    string str1 = "AAAA";
    string str2 = "ZZZZ";
    cout << str1.compare(str2) << endl;
    return 0;
}

You need to type cast else it is calling template

Upvotes: 0

Related Questions