为什么编译器在执行operator<<时不能使用类的std::string转换函数?

康桓瑋*_*康桓瑋 4 c++ iostream cout stdstring

考虑以下struct用户定义的转换函数,该函数可以将自身转换为const char*;

struct S {
  operator const char*() { return "hello"; }
};
Run Code Online (Sandbox Code Playgroud)

与此一起使用<iostream>,我们可以打印struct S没有错误消息的内容:

std::cout << S{} << '\n';
Run Code Online (Sandbox Code Playgroud)

但是如果我将返回类型更改为std::string

struct S {
  operator std::string() { return "hello"; }
};
Run Code Online (Sandbox Code Playgroud)

我收到此编译器错误消息:

<source>:11:13: error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'S')
11 |   std::cout << S{} << '\n';
   |   ~~~~~~~~~ ^~ ~~~
   |        |       |
   |        |       S
   |        std::ostream {aka std::basic_ostream<char>}
    <source>:11:18: note:   'S' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
11 |   std::cout << S{} << '\n';
   |                  ^
Run Code Online (Sandbox Code Playgroud)

为什么编译器不能使用std::string转换?内置类型和类类型的转换函数有区别吗?

son*_*yao 5

因为operator<<forstd::basic_string是一个带有 3 个模板参数的模板:

template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
    operator<<(std::basic_ostream<CharT, Traits>& os,
               const std::basic_string<CharT, Traits, Allocator>& str);
Run Code Online (Sandbox Code Playgroud)

并且模板参数推导中不会考虑隐式转换:

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

然后给出std::cout << S{};模板参数CharTTraits并且Allocator不能在第二个函数参数上推导。

另一方面,operator<<forconst char*则不存在这样的问题;给定std::cout << S{};,模板参数CharTTraits只能从第一个函数参数中推导出来。S推导后,将执行从到 的隐式转换const char*,并且调用正常。