像C ++中的Perl一样打印

时间:2013-06-12 17:14:34

标签: c++ printf

我可以在C ++中执行类似下面的Perl代码吗? 即重复$string n次?

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

5 个答案:

答案 0 :(得分: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。如果您使用printf,则仍需将其包装在().c_str()中,否则您将面临未定义的行为(即使您从未提及std::string)。

你可以改为重载一些其他非命名运算符,但是当你在重载中拥有 类型时重载运算符是非常粗鲁的,并且可能导致复杂化。

上述技术使用占位符类型x_opx_lhs来确保重载运算符仅在我们与命名运算符交互时生效。

选择*来包装我们的命名运算符x是因为操作是乘法的。

Bonus: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;
  }

尚未经过测试,但让我很开心。

答案 1 :(得分:1)

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

for (size_t i = 0; i < 4; ++i)
  printf ("%s", astring);
printf ("\n");

答案 2 :(得分: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;
}

答案 3 :(得分: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

答案 4 :(得分:0)

你可以使用for循环:

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

    cout<<string;