2

C++ で次の Perl コードのようなことはできますか?
つまり、$string n時間を複製しますか?

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

5 に答える 5

3

C++operator xには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-string ではなく文字列オブジェクトを使用する必要があります。その理由は、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 に答える
0

for ループを使用できます。

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

    cout<<string;
于 2013-06-13T04:52:59.650 に答える