This works, printing 1:
#include
struct Int {
int i;
operator int() const noexcept {return i;}
};
int main() {
Int i;
i.i
That operator is a free template function. User defined conversions do not get checked when matching against a template function arguments, it instead uses type pattern matching (substitution).
In theory a SFINAE overload using std::is_convertable<> would be able to do what you want, but that technique was not used when operator<< that outputs a std::string to a basic_ostream was defined.
A manual overload to output your class to basic_ostream<...> will fix your problem.
I would do this:
struct String {
std::string s;
operator std::string() const {return s;}
friend std::ostream& operator<<( std::ostream& os, String const& self) {
return os<
which has the added benefit of not creating a wasted copy.