首页 文章

为什么输出带转换运算符的类不适用于std :: string?

提问于
浏览
5

This works, printing 1

#include <iostream>

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

int main() {
    Int i;
    i.i = 1;
    std::cout << i;
}

但是,this fails to compile on GCC 4.8.1

#include <iostream>
#include <string>

struct String {
    std::string s;
    operator std::string() const {return s;}
};

int main() {
    String s;
    s.s = "hi";
    std::cout << s;
}

以下是错误的相关部分:

错误:'operator <<'不匹配(操作数类型是'std :: ostream '和'String')std :: cout << s;剪辑模板std :: basic_ostream <_CharT,_Traits>&std :: operator <<(std :: basic_ostream <_CharT,_Traits>&,const std :: basic_string <_CharT,_Traits,_Alloc>&)operator <<(basic_ostream < _CharT,_Traits>&__os,/ usr / include / c /4.8/bits/basic_string.h:2753:5:注意:模板参数推断/替换失败:main.cpp:25:18:注意:'String'不是派生自'const std :: basic_string <_CharT,_Traits,_Alloc>'std :: cout << s;

我只使用 std::coutstd::string ,它们具有相同的模板参数 . 我'm really not sure why this wouldn'能够像 Int 那样获取隐式转换 . 为什么它适用于 int ,而不是 std::string

2 回答

  • 7

    该运算符是一个免费的 template 函数 . 在匹配 template 函数参数时,不会检查用户定义的转换,而是使用类型模式匹配(替换) .

    理论上,使用 std::is_convertable<> 的SFINAE重载将能够执行您想要的操作,但是当 operator<< 输出 std::stringbasic_ostream<char> 时,未使用该技术 .

    将类输出到 basic_ostream<...> 的手动重载将解决您的问题 .

    我会这样做:

    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;
      }
    };
    

    它具有不创建浪费副本的额外好处 .

  • 1

    <<运算符似乎有一个重载池,其类型不是std :: string . 正如我通过使用clang编译器看到的那样 .

    编译器执行从String到std :: string的隐式转换,但它与任何已定义的<<运算符都不匹配 .

    如果为std :: string定义<<运算符,它将起作用

    #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;
    }
    

    您可以在此处找到有关同一问题的更多详细信息:http://forums.codeguru.com/showthread.php?432227-RESOLVED-Implicit-conversion-to-std-string

    正如一篇文章中所见;

    问题是运算符<<这里是一个模板,并且不能为TestClass类型进行模板实例化,因为在隐式实例化的模板的参数推导中可能没有考虑用户定义的转换(至少我在第14.7节中找不到) .1(隐式实例化) . 这会导致调用“std :: cout << obj <<'\ n';”的空重载集,从而导致错误 . 实例化是否已经发生并不重要 . 模板候选被选择为精确匹配的重载集(除了数组到指针衰减和const限定 - http://groups.google.co.in/group/com...29910b6?hl=en&) . 当你提供一个显式重载operator << with type std :: string,它是非模板并在重载集中相加,因此在执行重载解析/可调用匹配时调用隐式转换 .

相关问题