I am struggling to understand why the following code does not allow an implicit conversion to occur.
#include <string> using namespace std; struct HasConversionToString { HasConversionToString(const string& s_) : s{s_} {} string s; operator const string&() const { return s; } }; int main() { string s{"a"}; HasConversionToString obj{"b"}; return s < obj; }
Both clang and gcc fail to find a valid way to compare the two objects with errors along the lines of:
clang++ -std=c++14 -Wall -Wextra -pedantic conversion.cpp -o test conversion.cpp:13:12: error: invalid operands to binary expression ('string' (aka 'basic_string<char>') and 'HasConversionToString') return s < obj; ~ ^ ~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_pair.h:220:5: note: candidate template ignored: could not match 'pair' against 'basic_string' operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:298:5: note: candidate template ignored: could not match 'reverse_iterator' against 'basic_string' operator<(const reverse_iterator<_Iterator>& __x, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:348:5: note: candidate template ignored: could not match 'reverse_iterator' against 'basic_string' operator<(const reverse_iterator<_IteratorL>& __x, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:849:5: note: candidate template ignored: could not match '__normal_iterator' against 'basic_string' operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:856:5: note: candidate template ignored: could not match '__normal_iterator' against 'basic_string' operator<(const __normal_iterator<_Iterator, _Container>& __lhs, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:1089:5: note: candidate template ignored: could not match 'move_iterator' against 'basic_string' operator<(const move_iterator<_IteratorL>& __x, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:1095:5: note: candidate template ignored: could not match 'move_iterator' against 'basic_string' operator<(const move_iterator<_Iterator>& __x, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:4989:5: note: candidate template ignored: could not match 'basic_string<type-parameter-0-0, type-parameter-0-1, type-parameter-0-2>' against 'HasConversionToString' operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:5001:5: note: candidate template ignored: could not match 'const _CharT *' against 'HasConversionToString' operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs, ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:5013:5: note: candidate template ignored: could not match 'const _CharT *' against 'string' (aka 'basic_string<char>') operator<(const _CharT* __lhs, ^ 1 error generated.
whereas the following code works fine, when I explicitly cast the object to a string.
#include <string> using namespace std; struct HasConversionToString { HasConversionToString(const string& s_) : s{s_} {} string s; operator const string&() const { return s; } }; int main() { string s{"a"}; HasConversionToString obj{"b"}; return s < static_cast<string>(obj); }
based on the rules and examples listed on cppreference for implicit casts, I see no reason this shouldn't work. I assume that both clang and gcc didn't screw up the same thing, so I imagine that I've got a conceptual misunderstanding.