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

时间:2013-07-09 03:47:19

标签: c++ templates compiler-errors implicit-conversion

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&lt;&lt;'不匹配(操作数类型为'std :: ostream {aka std :: basic_ostream}'和'String')
         std :: cout&lt;&lt; S;

         

剪断

         

模板std :: basic_ostream&lt; _CharT,_Traits&gt;&amp; std :: operator&lt;&lt;(std :: basic_ostream&lt; _CharT,_Traits&gt;&amp;,const std :: basic_string&lt; _CharT,_Traits,_Alloc&gt;&amp;)
         运算符&lt;&lt;(basic_ostream&lt; _CharT,_Traits&gt;&amp; __os,

         

/ usr / include / c ++ / 4.8 / bits / basic_string.h:2753:5:注意:模板参数扣除/替换失败:
    main.cpp:25:18:注意:'String'不是来自'const std :: basic_string&lt; _CharT,_Traits,_ Alloc&gt;'
         std :: cout&lt;&lt; S;

  

我只使用std::coutstd::string,它们具有相同的模板参数。我真的不确定为什么这不能像Int那样获取隐式转换。为什么它适用于int,而不适用于std::string

2 个答案:

答案 0 :(得分:7)

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

理论上,使用std::is_convertable<>的SFINAE重载将能够执行您想要的操作,但在operator<<std::string输出basic_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 :(得分:1)

&lt;&lt;运算符似乎有一个重载池,其类型不是std :: string。 正如我在使用clang ++编译器时看到的那样。

编译器执行从String到std :: string的隐式转换,但它不匹配任何已定义的&lt;&lt;运营商。

如果您定义&lt;&lt; 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

如一篇文章中所见;

  

问题是运营商&lt;&lt;这是一个模板,并且不能为TestClass类型进行模板实例化,因为在隐式实例化的模板的参数推导中可能没有考虑用户定义的转换(至少我在第14.7.1节(隐式实例化)中找不到。)导致调用“std :: cout&lt;&lt; obj&lt;&lt;'\ n';”的空重载设置,从而导致错误。实例化是否已经发生并不重要。模板候选者被选中在完全匹配上设置重载(除了数组到指针衰减和const限定 - http://groups.google.co.in/group/com...29910b6?hl=en&)。

     

当您提供显式重载运算符时&lt;&lt;使用类型std :: string,它是非模板并在重载集中相加,因此在执行重载解析/可调用匹配时调用隐式转换。

相关问题