6

这有效,打印 1

#include <iostream>

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

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

但是,这无法在 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 {aka std::basic_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>'<br> std::cout << s;

我只使用std::coutand std::string,它们具有相同的模板参数。我真的不确定为什么它不能像Int. 为什么它可以工作int,但不能std::string

4

2 回答 2

8

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

理论上,SFINAE 重载 usingstd::is_convertable<>可以做你想做的事,但是当定义operator<<输出 astd::string到 a时,没有使用该技术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;
  }
};

这样做的另一个好处是不会创建浪费的副本。

于 2013-07-09T04:05:30.043 回答
2

<< 运算符似乎有一个类型为 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

正如在一篇文章中看到的那样;

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

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

于 2013-07-09T04:11:12.940 回答