Why does outputting a class with a conversion operator not work for std::string?

前端 未结 2 1126
Happy的楠姐
Happy的楠姐 2021-01-12 17:21

This works, printing 1:

#include 

struct Int {
    int i;
    operator int() const noexcept {return i;}
};

int main() {
    Int i;
    i.i          


        
相关标签:
2条回答
  • 2021-01-12 17:48

    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<char> 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<<self.s;
      }
    };
    

    which has the added benefit of not creating a wasted copy.

    0 讨论(0)
  • 2021-01-12 17:53

    The << operator seems to have a pool of overloads with types other than std::string. as I have seen by using the clang++ compiler.

    The compiler does the implicit conversion from String to std::string but it does not match any of the defined << operators.

    If you define the << operator for std::string it will work

    #include <iostream>
    #include <string>
    
    std::ostream& operator<<(std::ostream& s, const std::string& str)
    {
            s << str.c_str();
            return s;
    }
    
    struct String {
        std::string s;
        operator std::string() const {return s;}
    };
    
    int main() {
        String s;
        s.s = "hi";
        std::cout <<  s;
    }
    

    You can find more details on the same issue here: http://forums.codeguru.com/showthread.php?432227-RESOLVED-Implicit-conversion-to-std-string

    As seen in one post;

    The problem is the operator<< here is a template and no template instantiations can be made for the type TestClass since the user defined conversions are probably not being considered in argument deduction for templates for implicit instantiations (atleast I could not find in section 14.7.1 (Implicit instantiation). This results in an empty overload set for the call "std::cout << obj << '\n';" and hence the error. It does not matter if an instantiation already happened or not. Template candidates are chosen into overload set on exact matches (except for array to pointer decay and const qualification - http://groups.google.co.in/group/com...29910b6?hl=en&).

    When you provide an explicit overload operator<< with type std::string, it is non-template and adds up in the overload set and hence invoking the implicit conversion while doing overload resolution/a callable match.

    0 讨论(0)
提交回复
热议问题