C++ で次の Perl コードのようなことはできますか?
つまり、$string
n
時間を複製しますか?
printf ("%s\n",$string x 4);
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_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-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;
}
for ループを使用できます。
for(int i=0;i<n;i++)
cout<<string;