可以在打印缩进时重复使用 std::string_view 而不复制吗?

huangapple go评论94阅读模式
英文:

Can I repeat a std::string_view without copying when printing indentation?

问题

  1. #include <cstdio>
  2. #include <string_view>
  3. struct Logger {
  4. static inline constexpr std::string_view indent = " ";
  5. static inline int level = 0;
  6. Logger() {
  7. level++;
  8. }
  9. // ...
  10. void log(const std::string &msg) {
  11. std::printf(/* repeat indent 'level' times */);
  12. }
  13. };
英文:

I have a simple scene in C++ code.
I want to get a long string containing some repeated std::string_view; is there a way to achieve this without copying the string?

  1. #include &lt;cstdio&gt;
  2. #include &lt;string_view&gt;
  3. struct Logger {
  4. static inline constexpr std::string_view indent = &quot; &quot;;
  5. static inline int level = 0;
  6. Logger() {
  7. level++;
  8. }
  9. // ...
  10. void log(const std::string &amp;msg) {
  11. std::printf(/* repeat indent &#39;level&#39; times */);
  12. }
  13. };

答案1

得分: 3

C风格解决方案

std::printf允许您动态指定字段宽度。例如:

  1. #include &lt;cstdio&gt;
  2. int main() {
  3. int indent_length = 4;
  4. int indent_depth = 3;
  5. // 注意:将&quot;&quot;作为%s的参数传递
  6. std::printf(&quot;%*shi!&quot;, indent_length * indent_depth, &quot;&quot;);
  7. }

这将输出:

  1. hi!

我们可以使用这个技巧,因为缩进始终由一个字符组成,所以我们不需要重复一个完整的std::string_view
显然,如果您想要混合多个字符的缩进,这种方法就不起作用,但那将非常不寻常。

老式C++解决方案

但是,这是一种非常C风格的解决方案,您可以使用循环来避免复制:

  1. void log(std::string_view msg) {
  2. for (int i = 0; i &lt; level; ++i) {
  3. std::cout &lt;&lt; indent;
  4. }
  5. std::cout &lt;&lt; msg;
  6. }

然而,如果缩进不是不同字符的混合,
我们可以使用与上面相同的方法来避免这个循环:

  1. void log(std::string_view msg) {
  2. std::cout &lt;&lt; std::setw(indent_length * level) &lt;&lt; &quot;&quot; &lt;&lt; msg;
  3. }

如果您坚决要使用std::printf,我们仍然可以这样做:

  1. // 如果msg始终以null结尾
  2. std::printf(&quot;%s&quot;, msg.data());
  3. // 否则
  4. std::printf(&quot;%.*s&quot;, int(msg.length()), msg.data());

您的indent字符串可以以完全相同的方式打印。

英文:

C-Style Solution

std::printf allows you to dynamically specify the field width. For example:

  1. #include &lt;cstdio&gt;
  2. int main() {
  3. int indent_length = 4;
  4. int indent_depth = 3;
  5. // note: &quot;&quot; is passed as an argument for %s
  6. std::printf(&quot;%*shi!&quot;, indent_length * indent_depth, &quot;&quot;);
  7. }

This will output:

  1. hi!

We can use this trick because indentation always consist of one character, so we don't really have to repeat a full std::string_view.
Obviously, this wouldn't work if you wanted indentation that is a mixture of multiple characters, but that would be highly unusual.

Old-School C++ Solution

However, that is a very C-style solution, and you could just use a loop to avoid copying:

  1. void log(std::string_view msg) {
  2. for (int i = 0; i &lt; level; ++i) {
  3. std::cout &lt;&lt; indent;
  4. }
  5. std::cout &lt;&lt; msg;
  6. }

However, if the indent is not a mixture of different characters,
we can do a similar trick using std::cout as above to avoid this loop:

  1. void log(std::string_view msg) {
  2. std::cout &lt;&lt; std::setw(indent_length * level) &lt;&lt; &quot;&quot; &lt;&lt; msg;
  3. }

If you absolutely insist on using std::printf, we can still do:

  1. // if msg is always null-terminated
  2. std::printf(&quot;%s&quot;, msg.data());
  3. // otherwise
  4. std::printf(&quot;%.*s&quot;, int(msg.length()), msg.data());

Your indent string can be printed exactly the same way.

答案2

得分: 0

答案是,但 std::views::repeatstd::ranges::repeat_view 可以帮助您编写更简洁和更可读的代码。

作为替代,如果您事先知道最大缩进量,您可以初始化一个 std::arraystring_view,其维度为最大缩进量的数量,其中每个 string_view 都具有模式的递增重复。

英文:

The Answer to you question is NO,

but std::views::repeat or std::ranges::repeat_view can help you write more concise and more readable code.

In alternative, if you know a priori the max indentation, you could initialize a std::array of string_view, where the dimension is the number of max indentation, where each string_view, have incremental repetion of the pattern.

答案3

得分: 0

I would try to do the longest possible ident and then extract subview from it:

  1. using namespace std::string_view_literals;
  2. constexpr auto MaxIndentView = " "sv;
  3. constexpr std::string_view indentView(size_t n)
  4. {
  5. if (n * 4 > MaxIndentView.size()) {
  6. throw std::invalid_argument{"Max indentation reached"};
  7. }
  8. return MaxIndentView.substr(0, n * 4);
  9. }

But I think this is not what you actually need.

英文:

I would try do longest possible ident and then extract subview form it:

  1. using namespace std::string_view_literals;
  2. constexpr auto MaxIndentView = &quot; &quot;sv;
  3. constexpr std::string_view indentView(size_t n)
  4. {
  5. if (n * 4 &gt; MaxIndentView.size()) {
  6. throw std::invalid_argument{&quot;Max indentation reached&quot;};
  7. }
  8. return MaxIndentView.substr(0, n * 4);
  9. }

But I think this is not what you actually need.

huangapple
  • 本文由 发表于 2023年6月27日 16:56:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76563217.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定