【问题标题】:Why does <iostream> operator<< pick the apparently wrong overload?为什么 <iostream> operator<< 选择明显错误的重载?
【发布时间】:2018-01-04 19:46:11
【问题描述】:

考虑这段代码:

#include <iostream>
using namespace std;

class X {
public:
    operator const wchar_t* () const { return L"Hello"; }
};

void f(const void *) {
    wcout << L"f(const void*)\n";
}

void f(const wchar_t*) {
    wcout << L"f(const wchar_t*)\n";
}

int main() {
    X x;
    f(x);

    wcout << x;
}

输出为(用VS2015 C++编译器编译):

f(const wchar_t*)
00118B30

因此,编译器似乎为f 选择了预期 const wchar_t* 重载(因为存在从Xconst wchar_t* 的隐式转换)。

但是,wcout &lt;&lt; x 似乎选择了 const void* 重载,而不是 const wchar_t* 一个(打印地址,而不是 wchar_t 字符串)。

这是为什么?

PS 我知道打印X 的正确方法是像wostream&amp; operator&lt;&lt;(wostream&amp; , const X&amp;) 一样实现operator&lt;&lt; 的重载,但这不是问题。

【问题讨论】:

  • 这可能不是,但你的程序有undefined behaviorstd::coutstd::wcout 不能混搭。
  • @Rakete1111:这不是重点。随意使用 wcout 而不是 cout 来跟踪 f 的选定重载 :)
  • 这可能不是重点,但询问为什么具有未定义行为的程序会以某种方式运行没有任何意义,即使在您的情况下它不会改变任何东西。
  • 对于那些抱怨混合 wcout 和 cout 的人,我将代码更改为在 f 重载中的跟踪消息中使用 wcout 而不是 cout。相同的输出。
  • 注意,打印const void*的操作符是成员函数,打印const wchar_t*的操作符是非成员函数。我对查找规则不够熟悉,无法说明为什么这很重要,但我很确定它确实如此。

标签: c++ operator-overloading iostream


【解决方案1】:

因为在推导模板参数时不考虑转换函数:

// Non-template member function.
basic_ostream& basic_ostream::operator<<( const void* value );

// Template non-member function.
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os, 
                                         const CharT* s );

第二个声明不考虑转换operator const wchar_t* () const

我找不到标准报价,cppreference Template argument deduction, Implicit conversions 说:

类型推导不考虑隐式转换(除了上面列出的类型调整):这是重载解析的工作,稍后会发生。

【讨论】:

  • 如果你删除了非模板,它甚至不会编译,因为模板参数推导不会发生隐式转换。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-23
  • 2011-08-30
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2017-01-13
相关资源
最近更新 更多