2013-06-12 56 views
2

我可以在C++中執行下面的Perl代碼嗎?
即複製$stringn次?在C++中像Perl一樣打印

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

把它放在'for'循環中? – Kninnug

+0

我的代碼中有20多個這樣的printf,每個都有不同的字符串,每個都需要被複制不同的次數。爲每個放置'for'循環會使代碼變得醜陋。 – Jean

+1

在C + +醜陋的代碼?說並非如此。 – friedo

回答

3

雖然C++不具有operator x,C++是一個足夠靈活的語言,你可以寫一個名爲operator 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是因爲操作是類似乘法的。

獎勵:的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

我重載字符串和我的類型,而不是字符串和'int'。我的重載是'x_op' api的一部分。如果你重載了'std :: string * int',你正在搞亂你不擁有的類型的api。作爲一個例子,看看'std :: string'增加一個類似的重載時會發生什麼:raw overload變得模糊不清,而我的並不是因爲我擁有兩種類型之一。 – Yakk

+0

只要寫'std :: cout << x(foo,4)'就簡單多了。 – MSalters

1

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

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

關於你的Rep函數:據我所知,這個構造函數不存在。 –

+1

事實上,可以和'std :: string(5,'x')' – MSalters

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; 
} 
0

您可以只使用一個for循環:

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

    cout<<string; 
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