为什么输出带有转换运算符的类不适用于 std::string?
此作品
#include 结构体{国际我;运算符 int() const noexcept {return i;}};int main() {国际我;i.i = 1;std::cout <<一世;}
但是,编译失败 G rel="1:noreferr.
#include #include <字符串>结构字符串{std::string s;运算符 std::string() const {return s;}};int main() {字符串 s;s.s = "你好";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>&)
运算符<<(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>'
std::cout <<s;
我只使用具有相同模板参数的 std::cout
和 std::string
.我真的不知道为什么这不能像对 Int
那样进行隐式转换.为什么它适用于 int
,而不适用于 std::string
?
那个操作符是一个免费的 template
函数.当与 template
函数参数匹配时,不会检查用户定义的转换,而是使用类型模式匹配(替换).
理论上,使用 std::is_convertable<>
的 SFINAE 重载将能够做你想做的事,但是当 operator<<
时没有使用该技术将 std::string
输出到 basic_ostream
已定义.
手动重载将您的类输出到 basic_ostream<...>
将解决您的问题.
我会这样做:
struct String {std::string s;运算符 std::string() const {return s;}朋友 std::ostream&运算符<<( std::ostream& os, String const& self) {返回 os<
这有一个额外的好处,即不会创建浪费的副本.
This works, printing 1:
#include <iostream>
struct Int {
int i;
operator int() const noexcept {return i;}
};
int main() {
Int i;
i.i = 1;
std::cout << i;
}
However, this fails to compile on 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;
}
Here are the relevant parts of the error:
error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘String’)
std::cout << s;snip
template 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: note: template argument deduction/substitution failed:
main.cpp:25:18: note: ‘String’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’
std::cout << s;
I only use std::cout
and std::string
, which have the same template arguments. I'm really not sure why this wouldn't be able to pick up the implicit conversion like it did for Int
. Why does it work with int
, but not std::string
?
That operator is a free template
function. User defined conversions do not get checked when matching against a template
function arguments, it instead uses type pattern matching (substitution).
In theory a SFINAE overload using std::is_convertable<>
would be able to do what you want, but that technique was not used when operator<<
that outputs a std::string
to a basic_ostream<char>
was defined.
A manual overload to output your class to basic_ostream<...>
will fix your problem.
I would do this:
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;
}
};
which has the added benefit of not creating a wasted copy.
相关文章