我可以在 C++ 中执行类似以下 Perl 代码的操作吗?
即复制$string
n
时间?
printf ("%s\n",$string x 4);
虽然 C++ 没有operator x
,但 C++ 是一种足够灵活的语言,您可以编写一个命名运算符x
,其工作就是将字符串相乘:
#include <string>
namespace strop {
struct x_op {} x;
struct x_lhs { std::string s; };
x_lhs operator*( std::string s, x_op ) {
return {std::move(s)};
}
std::string operator*( x_lhs&& lhs, std::size_t rhs ) {
std::string retval;
for( std::size_t i = 0; i < rhs; ++i ) {
retval += lhs.s;
}
return retval;
}
}
采用:
#include <iostream>
using strop::x;
int main () {
std::string foo = "foo";
std::cout << (foo *x* 5) << "\n"; // if you prefer std::cout
printf("%s", (foo *x* 5).c_str()); // if you prefer printf
}
以上使用了一些琐碎的 C++11 特性,但不是本质上的。
C++03版本(效率较低):
#include <string>
namespace strop {
struct x_op {} x;
struct x_lhs { std::string s; x_lhs(std::string s_):s(s_) {} };
x_lhs operator*( std::string s, x_op ) {
return x_lhs(s);
}
std::string operator*( x_lhs lhs, std::size_t rhs ) {
std::string retval;
for( std::size_t i = 0; i < rhs; ++i ) {
retval += lhs.s;
}
return retval;
}
}
有趣的是,这适用于字符串文字:
std::cout << "bar" *x* 3 << "\n";
std::string
因为它们被隐式地变成了s 。如果您正在使用printf
,则仍然需要将其包装在 中().c_str()
,否则您将面临未定义行为的风险(即使您从未提及std::string
)。
相反,您可以重载其他一些未命名的运算符,但是当您在重载中既不拥有任何类型时,重载运算符也是非常粗鲁的,并且可能导致复杂化。
上述技术使用 and 的占位符类型x_op
来x_lhs
确保重载的运算符仅在我们与命名运算符交互时才会生效。
选择*
包装我们的命名运算符x
是因为该操作类似于乘法。
奖励: 的疯狂版本operator*
,它使用 rhs 的位值来减少字符串争吵的数量:
std::string operator*( x_lhs lhs, std::size_t rhs ) {
std::string retval;
auto done = [rhs]( std::size_t n ) {
return !(i < (sizeof(rhs)*8) && !(rhs &~std::size_t((1<<i)-1)));
};
for( int i = 0; true; ++i) {
if (!done(i+1)) {
if (rhs & (1 << i))
retval += lhs;
lhs += lhs;
continue;
} else {
// high bit must be set, or we'd be done before, unless rhs was 0:
if (rhs != 0)
retval += std::move(lhs);
break;
}
}
return retval;
}
这还没有经过测试,但让我很开心。
不,不是直接的。你需要自己做:
for (size_t i = 0; i < 4; ++i)
printf ("%s", astring);
printf ("\n");
前言:重载运算符是一种微妙的做法。如果您不小心,可能会导致代码难以阅读和维护。那就是说...
您可以尝试重载operator*()
,但为了完成这项工作,您需要使用字符串对象而不是裸 c 字符串。原因是 C++ 不允许重载仅引用内置类型的运算符。该类std::string
未内置于该语言中。例如,以下函数将对 std::string 对象执行您想要的操作。请注意,返回类型是 const char* 以兼容printf()
.
const char* operator*(const std::string& input, size_t repeat)
{
std::string output;
for (size_t ii=0; ii<repeat; ++ii)
output += input;
return output.c_str();
}
如果字符串存储在 std::string 对象中,则可以使用该函数使用您喜欢的语法:
int main(int argc, char** argv)
{
std::string input = argv[1];
printf("%s\n", input*3); // works
printf("%s\n", std::string(argv[1])*3); // works
//printf("%s\n", argv[1]*3); // compile error
}
一种更自然的 C++ 方法是使用<iostream>
,它不需要您在重载运算符中混合char*
和键入。std::string
std::string operator*(const std::string& input, size_t repeat)
{
std::string output;
for (size_t ii=0; ii<repeat; ++ii)
output += input;
return output;
}
int main(int argc, char** argv)
{
std::cout << std::string(argv[1])*3 << std::endl;
}
就像@Yakk 的重载一样令人印象深刻,为什么不定义一个简单的函数呢?
std::string repeat(const std::string& s, int times) {
std::string res;
res.reserve(s.size() * times);
for (int i = 0; i < times; ++i)
res += s;
return s;
}
然后你可以做
std::cout << repeat("foo", 4) << std::endl;
打印foofoofoofoo
。
您可以只使用 for 循环:
for(int i=0;i<n;i++)
cout<<string;