We upgrade our codebase from c++17 to c++20 lately, and some code does not work as before. I take the following simplified sample code as show case here.
None of the overloaded compare operators is called. Instead, it converts to const char* to compare. Why is that?
#include <iostream>
#include <string_view>
class FooString {
public:
FooString& operator=(const FooString& src) {
if (this != &src) {
m_data = src.m_data;
}
return *this;
}
FooString& operator=(FooString&& src) {
m_data = std::move(src.m_data);
return *this;
}
FooString& operator=(const char* value) {
m_data = value;
return *this;
}
FooString& operator=(std::string value) {
m_data = std::move(value);
return *this;
}
bool operator==(const FooString& value) const {
return (0 == compare(m_data, value.m_data));
}
bool operator!=(const FooString& value) const{
printf("__%d__\n", __LINE__);
return (compare(m_data, value.m_data));
}
bool operator<=(const FooString& value) const {
printf("__%d__\n", __LINE__);
return (0 >= compare(m_data, value.m_data));
}
bool operator>=(const FooString& value) const{
printf("__%d__\n", __LINE__);
return (0 <= compare(m_data, value.m_data));
}
bool operator<(const FooString& value) const {
printf("__%d__\n", __LINE__); // this was called before c++20
return (0 > compare(m_data, value.m_data));
}
bool operator>(const FooString& value) const {
printf("__%d__\n", __LINE__);
return (0 < compare(m_data, value.m_data));
}
operator const char*() const {
printf("__%d__\n", __LINE__); // this function gets called with c++20
return m_data.c_str();
}
const std::string& str() const {
return m_data;
}
const char* c_str() const {
return m_data.c_str();
}
protected:
virtual int compare(std::string_view str1, std::string_view str2) const {
return str1.compare(str2);
}
private:
std::string m_data;
};
int main()
{
FooString str1;
str1 = "test1";
FooString str2;
str2 = "test1";
std::tuple<const FooString&> k1(std::tie(str1));
std::tuple<const FooString&> k2(std::tie(str2));
if (k1 < k2) {
printf("k1 < k2\n");
} else {
printf("k1 >= k2\n");
}
return 0;
}
Live Demo Switch between -std=c++17 and -std=c++20 to see the difference.
I search a bit around and learnt this is due to c++20 impose totally ordering for tuple reference. I thought we have provided the totally ordering operators !=, ==, etc. no? or why the overloaded operators are shadowed by the conversion operator const char*? Now the comparsion with pointer address with c++20 depends on the machine ordering...
any insights are welcome. Also this is a breaking feature from c++20, no?
printfin c++.std::coutwas available more or less since the beginning, and recently (c++23) we also have the more modernstd::print. See: 'printf' vs. 'cout' in C++.