关于ofstream的警告,但不是ostream的警告.有什么不同?

Aar*_*aid 7 c++ compiler-warnings

这并不重要.但我很好奇这个警告何时出现.我真正的问题是为什么ostream和ofstream被区别对待.

struct Test {
    int y;
    Test(int k) : y(k) {}
};
Run Code Online (Sandbox Code Playgroud)

使用这个简单的结构,编译器可以看到一个int可以转换为Test.

因此,我收到此代码的警告:

std :: ofstream& operator<<  (std :: ofstream& os, const Test& t)
{
    os << t.y;
    return os;
}
Run Code Online (Sandbox Code Playgroud)

当它看到os << t.y它不知道我是否想要推送名为ty的int,或者我是否想先将int转换为Test然后再推送它.这看起来很奇怪,你会认为它更喜欢非转换的int重载ofstream& operator<< (ofstream &os, int).

g ++(Ubuntu 4.4.3-4ubuntu5)4.4.3:

template_expl.cpp: In function ‘std::ofstream& operator<<(std::ofstream&, const Test&)’:
template_expl.cpp:15: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
/usr/include/c++/4.4/bits/ostream.tcc:105: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
template_expl.cpp:13: note: candidate 2: std::ofstream& operator<<(std::ofstream&, const Test&)
Run Code Online (Sandbox Code Playgroud)

无论如何,解决这个问题的一种方法是将Test中的构造函数标记为explicit.我可以忍受这一点.但奇怪的是,如果ofstream被替换ostream,那么警告就会消失.知道为什么吗?

Arm*_*yan 7

你打电话的时候

os << t.y;
Run Code Online (Sandbox Code Playgroud)

你有2个候选人:

ostream& operator << (ostream&, int) //1
Run Code Online (Sandbox Code Playgroud)

ofstream& operator << (ofstream&, Test) //2
Run Code Online (Sandbox Code Playgroud)

没有这样的候选人

ofstream& operator << (ofstream&, int) //3
Run Code Online (Sandbox Code Playgroud)

根据重载决策规则,1和2都不适合您的呼叫.因此警告.如果是ostream,1显然是更好的匹配,因为两个参数完全匹配.

最好的解决方案是配合使用std::ostream.为什么需要专门为文件流重载.如果您需要将其流式传输到字符串中该怎么办?重载输出流操作符std::ostream(或甚至是模板化版本std::basic_ostream)并让编译器处理其余的操作.


Ker*_* SB 5

正如警告告诉您的那样,ofstream两种解释都需要转换:

  1. ofstream& -> ostream&static_cast<ostream&>(os) << t.y,

  2. int -> Testos << static_cast<Test>(t.y)

如果你ostream&直接使用,那么int-interpretation 不需要转换,因此是首选.