This question already has answers here:
Operator overloading : member function vs. non-member function?
(2 answers)
Is there any advantage to implementing functions as free functions rather than members in C++?
(6 answers)
Closed 26 days ago.
This post was edited and submitted for review 26 days ago and failed to reopen the post:
Original close reason(s) were not resolved
I cpp doc we see:
template< class CharT, class Traits, class Alloc >
bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
const CharT* rhs ); (until C++20)
template< class CharT, class Traits, class Alloc >
constexpr bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
const CharT* rhs ); (since C++20)
template< class CharT, class Traits, class Alloc >
bool operator==( const CharT* lhs,
const std::basic_string<CharT,Traits,Alloc>& rhs ); (until C++20)
My question is:
Why if c++20 gives us feature to 'reverse' operators equality operator is still non class member function? What is the reason?
Update:
Code example:
#include <iostream>
#include <string>
struct MyString {
std::string m_val;
MyString(const char* val) : m_val(val) {}
bool operator==(const char* other) const { return m_val == other; }
};
int main() {
MyString tata = "tata";
std::cout << ("mama" == tata) << std::endl;
return 0;
}
This code compiles with c++20 but not with c++17.
Here equality operator is a member of a class. Why did not std implementation go this way?
Related
I don't understand why this code compiles and runs:
std::string s;
std::cin >> s;
// if (s == "done") { // version 1
if ("done" == s) { // version 2
std::cout << "We're done here" << std::endl;
}
Version 1 works as I would expect. The compiler sees that s is a std::string, and uses the std::string definition of == to do the comparison.
However, when comparing a variable to an explicit value, I like to use the trick of putting the explicit value first in case one day I accidentally use = instead and do an assignment instead. Hence, version 2.
Now version 2 works on my compiler (llvm on MacOS) the same way as version 1, but I'm not sure why (or if it's a reliable result). I would have though that the compiler sees "done" as a char* explicit value (literal) and says, "hey, == makes no sense on char*" and give me a compilation error message. But my compiler doesn't do that, it compiles without complaint and the code executes the same way as version 1.
What am I misunderstanding here?
The type of "done" is not char*. It is const char[5].
But in any case, it works because if you include <string>, which you must have to use std::string, then (before C++20) you include an overload for operator== of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
const CharT* rhs );
and one of the form
template< class CharT, class Traits, class Alloc >
bool operator==( const CharT* lhs,
const std::basic_string<CharT,Traits,Alloc>& rhs );
See https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp for reference.
std::string is just std::basic_string with CharT being char and Traits and Alloc being some defaults that don't matter here.
So effectively one overload accepts a const std::string& as left-hand argument and const char* as right-hand argument, and the other accepts the reverse.
const char[N] can be deduced as const char* and it is implicitly convertible to the latter for every N, so the first overload is viable for s == "done" and the second for "done" == s.
The standard library is written with these overloads specifically so that your use will work. Your approach of using the "done" == s variant makes sense, because "done" = s would indeed be an error. operator= can only be overloaded with a class type on the left-hand side.
Since C++20, the overloads look a bit different. In particular it isn't necessary to have both anymore. The compiler now automatically tries overloads matching the rewritten expression with reversed operands of == when doing overload resolution.
to an explicit value,
explicit constant
I am not sure what you mean here, but "explicit value" and "explicit constant" are not standard terminology. Probably you mean "(string) literal" instead.
and says, "hey, == makes no sense on char*"
It doesn't work that way. As soon as either side of == is a class type, the compiler has to consider that == may be overloaded to match the expression.
For the class template std::basic_string the equality operator == is overloaded in particular the following way
template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);
So the first argument maybe a C string literal without requiring any conversion (except the standard implicit conversion from an array type to pointer to the array element type).
Actually the operator has three overloads
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const basic_string<charT, traits, Allocator>& rhs) noexcept;
template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);
and
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const charT* rhs);
I have the following class definition:
template <typename T>
class MyBox {
public:
MyBox(T value) { _value = value; }
operator T() const { return _value; }
private:
T _value;
};
typedef MyBox<int> MyInt;
typedef MyBox<std::string> MyString;
When I try to use operators on my typedefs like this
bool first = MyInt(1) == MyInt(1); // works
bool second = std::string(MyString("a")) == std::string(MyString("a")); //works
bool third = MyString("a") == MyString("a"); // does not compile
the compiler complains about the third comparison
no operator "==" matches these operands. operand types are: MyString == MyString
and this happens with any other non-primitve boxing (e.g. MyBox<float> works but MyBox<std::map<int,int> > not. Why is that so?
This is especially unclear to me because for the first and second comparison the operator T() is used - why can't that be done automatically for MyString as well?
UPDATE: Is there a simple solution to this other than providing the specific operators for each non-primitive template? And what to do with MyString("a") == std::string("a")?
The reasons on why it works for built-in types, but does't work for custom types is answered in the following SO quesiton: using user-defined conversions with implicit conversions in comparisons. In short, this is because type conversion does not happen for template-deduced types. And while built-in operator== for int is not a template (and thus can be found using type conversion when MyBox<int> is used), operator== for std::string is a template.
However, the question mentioned above doesn't have details on how to solve this problem. Here is how: add following free functions
template<class T>
bool operator==(const MyBox<T>& lhs, const MyBox<T>& rhs) {
return static_cast<const T&>(lhs) == static_cast<const T&>(rhs);
}
template<class T>
bool operator==(const MyBox<T>& lhs, const T& rhs) {
return static_cast<const T&>(lhs) == rhs;
}
template<class T>
bool operator==(const T& lhs, const MyBox<T>& rhs) {
return lhs == static_cast<const T&>(rhs);
}
Consider the following code snippet:
#include <iostream>
int main() {
std::string str = "Hello";
const char *cstr = "Hello";
if (cstr == str) {
std::cout<<"Both are same string.";
}
return 0;
}
I am having difficulty guessing how the const char* and string comparison work:
if (cstr == str) {
As per my understanding, the overloaded operator of the left operand (cstr in this case) is called with str as the argument. Now there is no overloading of == for const char*. So how does the above comparison even work?
Had the comparison been str==cstr, I would have no issues accepting it (as == for std::string is overloaded and it accepts const char* as an argument for comparison).
Note:- I am using gcc-4.8.1 for compiling the above code.
As per my understanding, the overloaded operator of the left operand (cstr in this case) is called with str as the argument. Now there is no overloading of == for const char*.
The operator is actually for std::string, and looks conceptually similar to this:
bool operator==(const char* const lhs, const std::string& rhs);
(though it reality it is templated).
This operator of std::string is added specifically for the operation you mention (comparing a std::string with a char*, when the char* is provided as the left-hand-side operand in the comparison).
Had the comparison been str==cstr, I would have no issues accepting it (as == for std::string is overloaded and it accepts const char* as an argument for comparison).
Both are present (specifically to support this situation).
From http://en.cppreference.com/w/cpp/string/basic_string/operator_cmp.
Compare a basic_string object and null-terminated array of T
template< class CharT, class traits, class Alloc >
bool operator==(const CharT* lhs, const basic_string<CharT,Traits,Alloc>& rhs);
template< class CharT, class traits, class Alloc >
bool operator==(const basic_string<CharT,Traits,Alloc>& lhs, const CharT* rhs);
...
std::string somestring;
/*...*/
if("STRING_LITERAL" == somestring)
std::cout << "Strings are Equal" << std::endl;
In the sample code above, how does a C++ compiler interpret the ==
operator? As the == operator overloaded by the string class?
If you're using std::string then you should have #included the <string> header. Assuming this is the case then the operator== selected should be the non-member template function from <string> with appropriate template parameters deduced. (ISO/IEC 14882:2003 21.3.7.2 [lib.string::operator==])
template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs,
const basic_string<charT,traits,Allocator>& rhs);
The std::string class (strictly class template specialization) doesn't contain any member overloads for operator==.
Yes. The operator== is implemented as a free standing function, that's why the positioning is irrelevant. It could be
bool operator==(const string& str1, const char* str2){
// ...
}
or
bool operator==(const char* str1, const string& str2){
// ...
}
or even a simple
bool operator==(const string& str1, const string& str2){
// ...
}
With an automatic conversion from char const* to string, as the relevant constructor of std::string is non-explicit.
There is an overload of operator== that does the right thing:
template <class charT, class traits, class Allocator>
bool operator==(const charT* lhs,
const basic_string<charT, traits, Allocator>& rhs);
You can find it in 21.3 ยง1 of the C++0x FDIS on page 635.
From http://www.cplusplus.com/reference/string/operators/ , these overloads are defined:
bool operator== ( const string& lhs, const string& rhs );
bool operator== ( const char* lhs, const string& rhs );
bool operator== ( const string& lhs, const char* rhs );
Note that these are global functions, not methods of the string class (but they'll be implemented using string::compare().
From wikipedia:
// A class template to express an equality comparison interface.
template<typename T> class equal_comparable
{
friend bool operator==(T const &a, T const &b) { return a.equal_to(b); }
friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};
class value_type
// Class value_type wants to have == and !=, so it derives from
// equal_comparable with itself as argument (which is the CRTP).
: private equal_comparable<value_type>
{
public:
bool equal_to(value_type const& rhs) const; // to be defined
};
This is supposed to be the Barton-Nackman, that could achieve compile-time dimensional analysis (checking if some operations applied to variables end up in comparable numbers, like speed comparable to space/time but no acceleration).
Could anyone explain me how, or at least explain me what are the NON-TEMPLATE members?
Thanks
The rules of the language have changed since the pattern was invented, although care was taken not to break it. In other words, as far as I can tell, it still works but for different reasons than it originally did. I don't think I would base an attempt at dimensional analysis on this pattern as I think there are better ways of doing that today.
I also think the example is too trivial to be helpful. As already stated the instantiation of equal_comparable<value_type> causes operator== and operator!= for value_type to appear. Since they are non-members it doesn't matter that the inheritance is private, they're still eligable for selection when resolving a call. It's just hard to see the point in this example. Let's say however, that you add a template parameter to equal_comparable and a few other things:
template<typename U, typename V> class equal_comparable
{
friend bool operator==(U const &a, V const &b) { return a.equal_to(b); }
friend bool operator!=(U const &a, V const &b) { return !a.equal_to(b); }
};
class some_other_type
{
bool equal_to(value_type const& rhs) const;
};
class value_type
: private equal_comparable<value_type>, // value_type comparable to itself
private equal_comparable<some_other_type> // value_type comparable to some_other_type
{
public:
bool equal_to(value_type const& rhs) const;
bool equal_to(some_other_type const& rhs) const;
};
Disclaimer: I have no idea if this is the way it's supposed to be used but I'm reasonably sure that it would work as described.
These are actually nontemplate nonmembers - the comparison operators in the base template - they get used by the ADL for the derived class. A template member would be something like:
class C
{
...
template < typename T > void DoGreatStuff( T t ) { ... }
...
};
The instantiation of equal_comparable<value_type> in value_type class causes the compiler to generate two comparison functions:
friend bool operator==(value_type const &a, value_type const &b) { return a.equal_to(b); }
friend bool operator!=(value_type const &a, value_type const &b) { return !a.equal_to(b); }
These functions are nontemplate since they do not depend on any template parameter, but they are also nonmembers since they are declared as friend.