为什么编译器在执行operator<<时不能使用class的std::string转换函数?
Why can't the compiler use the std::string conversion function of the class when perform operator<<?
考虑下面的 struct
和一个用户定义的转换函数,可以将其自身转换为 const char*
;
struct S {
operator const char*() { return "hello"; }
};
这与 <iostream>
一起工作,我们可以打印 struct S
而没有错误消息:
std::cout << S{} << '\n';
但是如果我将 return 类型更改为 std::string
:
struct S {
operator std::string() { return "hello"; }
};
我收到此编译器错误消息:
<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';
| ^
为什么编译器不能使用 std::string
转换?内置和class类型的转换函数有区别吗?
因为operator<<
for std::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);
并且在template argument deduction中不会考虑隐式转换:
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
然后给定 std::cout << S{};
,模板参数 CharT
、Traits
和 Allocator
无法在第二个函数参数上推导。
另一方面,operator<<
for const char*
没有这样的问题;给定 std::cout << S{};
,模板参数 CharT
和 Traits
只能从第一个函数参数推导出来。推导后,会进行S
到const char*
的隐式转换,调用正常
考虑下面的 struct
和一个用户定义的转换函数,可以将其自身转换为 const char*
;
struct S {
operator const char*() { return "hello"; }
};
这与 <iostream>
一起工作,我们可以打印 struct S
而没有错误消息:
std::cout << S{} << '\n';
但是如果我将 return 类型更改为 std::string
:
struct S {
operator std::string() { return "hello"; }
};
我收到此编译器错误消息:
<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';
| ^
为什么编译器不能使用 std::string
转换?内置和class类型的转换函数有区别吗?
因为operator<<
for std::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);
并且在template argument deduction中不会考虑隐式转换:
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
然后给定 std::cout << S{};
,模板参数 CharT
、Traits
和 Allocator
无法在第二个函数参数上推导。
另一方面,operator<<
for const char*
没有这样的问题;给定 std::cout << S{};
,模板参数 CharT
和 Traits
只能从第一个函数参数推导出来。推导后,会进行S
到const char*
的隐式转换,调用正常