2

我可以在 C++ 中执行类似以下 Perl 代码的操作吗?
即复制$string n时间?

printf ("%s\n",$string x 4);
4

5 回答 5

3

虽然 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_opx_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;
  }

这还没有经过测试,但让我很开心。

于 2013-06-12T17:50:26.550 回答
1

不,不是直接的。你需要自己做:

for (size_t i = 0; i < 4; ++i)
  printf ("%s", astring);
printf ("\n");
于 2013-06-12T17:23:23.433 回答
1

前言:重载运算符是一种微妙的做法。如果您不小心,可能会导致代码难以阅读和维护。那就是说...

您可以尝试重载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;
}
于 2013-06-12T17:51:34.210 回答
1

就像@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

于 2013-06-13T10:52:51.337 回答
0

您可以只使用 for 循环:

for(int i=0;i<n;i++)

    cout<<string;
于 2013-06-13T04:52:59.650 回答