重载 << 运算符以将 " " 更改为 "\n"
Overload << operator to change " " to "\n"
我正在尝试超载
<<
运算符。例如
cout << a << " " << b << " "; // I am not allowed to change this line
给出了我必须以格式打印它
<literal_valueof_a><"\n>
<literal_valueof_b><"\n">
<"\n">
我试图重载 << 运算符,将字符串作为参数,但它不起作用。所以我猜字面
" "
不是字符串。如果不是那么它是什么。以及如何超载它?
请帮忙;
完整代码
//Begin Program
// Begin -> Non - Editable
#include <iostream>
#include <string>
using namespace std;
// End -> Non -Editable
//---------------------------------------------------------------------
// Begin -> Editable (I have written )
ostream& operator << (ostream& os, const string& str) {
string s = " ";
if(str == " ") {
os << '\n';
}
else {
for(int i = 0; i < str.length(); ++i)
os << str[i];
}
return os;
}
// End -> Editable
//--------------------------------------------------------------------------
// Begin -> No-Editable
int main() {
int a, b;
double s, t;
string mr, ms;
cin >> a >> b >> s >> t ;
cin >> mr >> ms ;
cout << a << " " << b << " " ;
cout << s << " " << t << " " ;
cout << mr << " " << ms ;
return 0;
}
// End -> Non-Editable
//End Program
输入和输出
输入
30 20 5.6 2.3 hello world
输出
30
20
5.6
2.3
hello
world
您可能希望使用用户定义的文字,例如
struct NewLine {};
std::ostream& operator << (std::ostream& os, NewLine)
{
return os << "\n";
}
NewLine operator ""_nl(const char*, std::size_t) // "nl" for newline
{
return {};
}
可以按如下方式使用。
int main(int, char **)
{
std::cout << 42 << ""_nl << "43" << ""_nl;
return 0;
}
这里注意三件事:
- 您可以传递任何后跟文字标识符的字符串文字,
""_nl
与 " "_nl
或 "hello, world"_nl
的作用相同。您可以通过调整返回 NewLine
对象的函数来更改它。
- 这个解决方案更像是一个笨拙和令人困惑的 hack。我能想象的唯一真实用例是关于在以后的时间点轻松更改行为的选项。
- 当做一些非标准的事情时,最好让它明显和明确 - 在这里,用户定义的文字确实闪耀,因为
<< ""_nl
比 << " "
更容易引起读者的注意.
" "
是一个长度为 1 的字符串文字,因此类型为 const char[2]
。 std::string
不相关。
理论上,因此您可以将其重载为:
auto& operator<<(std::ostream& os, const char (&s)[2]) {
return os << (*s == ' ' && !s[1] ? +"\n" : +s);
}
虽然这胜过所有其他重载,但现在事情变得非常棘手。问题是 some_ostream << " "
可能并不少见,即使在模板中也是如此,现在不再解析为调用 the standard function。这些模板现在在受影响的翻译单元中具有与未受影响的翻译单元不同的定义,因此违反了单一定义规则。
您应该做的,不是尝试将全局解决方案应用于非常局部的问题:
最好修改当前流式传输 space 字符的代码。
或者,编写您自己的流缓冲区,根据需要将其转换为换行符。
当然可以,我已经测试过了。它应该是可移植的,因为您正在指定 <iostream>
中包含的模板化函数 operator<<()
的覆盖。您代码中的 " "
字符串不是 std::string
,而是 C 风格的字符串(即 const char *
)。以下定义工作正常:
ostream& operator << (ostream& os, const char *str) {
if(strcmp(str, " ") == 0) {
os << '\n';
} else {
// Call the standard library implementation
operator<< < std::char_traits<char> > (os, str);
}
return os;
}
注意 std::char_traits<char>
之后的 space 仅当你是 pre-c++11 时才需要。
编辑 1
我同意 Deduplicator 的观点,即这是一个具有潜在危险的解决方案,因为它可能会在代码库的其他地方造成不良后果。如果仅在当前文件中需要它,您可以将其设为静态函数(通过将其放在未命名的名称space 中)。或许,如果您分享更多关于您问题的细节,我们可以为您提出一个更简洁的解决方案。
我正在尝试超载
<<
运算符。例如
cout << a << " " << b << " "; // I am not allowed to change this line
给出了我必须以格式打印它
<literal_valueof_a><"\n>
<literal_valueof_b><"\n">
<"\n">
我试图重载 << 运算符,将字符串作为参数,但它不起作用。所以我猜字面
" "
不是字符串。如果不是那么它是什么。以及如何超载它? 请帮忙;
完整代码
//Begin Program
// Begin -> Non - Editable
#include <iostream>
#include <string>
using namespace std;
// End -> Non -Editable
//---------------------------------------------------------------------
// Begin -> Editable (I have written )
ostream& operator << (ostream& os, const string& str) {
string s = " ";
if(str == " ") {
os << '\n';
}
else {
for(int i = 0; i < str.length(); ++i)
os << str[i];
}
return os;
}
// End -> Editable
//--------------------------------------------------------------------------
// Begin -> No-Editable
int main() {
int a, b;
double s, t;
string mr, ms;
cin >> a >> b >> s >> t ;
cin >> mr >> ms ;
cout << a << " " << b << " " ;
cout << s << " " << t << " " ;
cout << mr << " " << ms ;
return 0;
}
// End -> Non-Editable
//End Program
输入和输出 输入
30 20 5.6 2.3 hello world
输出
30
20
5.6
2.3
hello
world
您可能希望使用用户定义的文字,例如
struct NewLine {};
std::ostream& operator << (std::ostream& os, NewLine)
{
return os << "\n";
}
NewLine operator ""_nl(const char*, std::size_t) // "nl" for newline
{
return {};
}
可以按如下方式使用。
int main(int, char **)
{
std::cout << 42 << ""_nl << "43" << ""_nl;
return 0;
}
这里注意三件事:
- 您可以传递任何后跟文字标识符的字符串文字,
""_nl
与" "_nl
或"hello, world"_nl
的作用相同。您可以通过调整返回NewLine
对象的函数来更改它。 - 这个解决方案更像是一个笨拙和令人困惑的 hack。我能想象的唯一真实用例是关于在以后的时间点轻松更改行为的选项。
- 当做一些非标准的事情时,最好让它明显和明确 - 在这里,用户定义的文字确实闪耀,因为
<< ""_nl
比<< " "
更容易引起读者的注意.
" "
是一个长度为 1 的字符串文字,因此类型为 const char[2]
。 std::string
不相关。
理论上,因此您可以将其重载为:
auto& operator<<(std::ostream& os, const char (&s)[2]) {
return os << (*s == ' ' && !s[1] ? +"\n" : +s);
}
虽然这胜过所有其他重载,但现在事情变得非常棘手。问题是 some_ostream << " "
可能并不少见,即使在模板中也是如此,现在不再解析为调用 the standard function。这些模板现在在受影响的翻译单元中具有与未受影响的翻译单元不同的定义,因此违反了单一定义规则。
您应该做的,不是尝试将全局解决方案应用于非常局部的问题:
最好修改当前流式传输 space 字符的代码。
或者,编写您自己的流缓冲区,根据需要将其转换为换行符。
当然可以,我已经测试过了。它应该是可移植的,因为您正在指定 <iostream>
中包含的模板化函数 operator<<()
的覆盖。您代码中的 " "
字符串不是 std::string
,而是 C 风格的字符串(即 const char *
)。以下定义工作正常:
ostream& operator << (ostream& os, const char *str) {
if(strcmp(str, " ") == 0) {
os << '\n';
} else {
// Call the standard library implementation
operator<< < std::char_traits<char> > (os, str);
}
return os;
}
注意 std::char_traits<char>
之后的 space 仅当你是 pre-c++11 时才需要。
编辑 1
我同意 Deduplicator 的观点,即这是一个具有潜在危险的解决方案,因为它可能会在代码库的其他地方造成不良后果。如果仅在当前文件中需要它,您可以将其设为静态函数(通过将其放在未命名的名称space 中)。或许,如果您分享更多关于您问题的细节,我们可以为您提出一个更简洁的解决方案。