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

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

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

问题

#include <cstdio>
#include <string_view>

struct Logger {
    static inline constexpr std::string_view indent = "    ";
    static inline int level = 0;

    Logger() {
        level++;
    }

    // ...
    
    void log(const std::string &msg) {
        std::printf(/* repeat indent 'level' times */);
    }
};
英文:

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?

#include &lt;cstdio&gt;
#include &lt;string_view&gt;

struct Logger {
    static inline constexpr std::string_view indent = &quot;    &quot;;
    static inline int level = 0;

    Logger() {
        level++;
    }

    // ...
    
    void log(const std::string &amp;msg) {
        std::printf(/* repeat indent &#39;level&#39; times */);
    }
};

答案1

得分: 3

C风格解决方案

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

#include &lt;cstdio&gt;

int main() {
    int indent_length = 4;
    int indent_depth = 3;

    // 注意:将&quot;&quot;作为%s的参数传递
    std::printf(&quot;%*shi!&quot;, indent_length * indent_depth, &quot;&quot;);
}

这将输出:

            hi!

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

老式C++解决方案

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

void log(std::string_view msg) {
    for (int i = 0; i &lt; level; ++i) {
        std::cout &lt;&lt; indent;
    }
    std::cout &lt;&lt; msg;
}

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

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

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

// 如果msg始终以null结尾
std::printf(&quot;%s&quot;, msg.data());

// 否则
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:

#include &lt;cstdio&gt;

int main() {
    int indent_length = 4;
    int indent_depth = 3;

    // note: &quot;&quot; is passed as an argument for %s
    std::printf(&quot;%*shi!&quot;, indent_length * indent_depth, &quot;&quot;);
}

This will output:

            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:

void log(std::string_view msg) {
    for (int i = 0; i &lt; level; ++i) {
        std::cout &lt;&lt; indent;
    }
    std::cout &lt;&lt; msg;
}

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:

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

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

// if msg is always null-terminated
std::printf(&quot;%s&quot;, msg.data());

// otherwise
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:

using namespace std::string_view_literals;

constexpr auto MaxIndentView = "                                            "sv;

constexpr std::string_view indentView(size_t n)
{
    if (n * 4 > MaxIndentView.size()) {
        throw std::invalid_argument{"Max indentation reached"};
    }
    return MaxIndentView.substr(0, n * 4);
}

But I think this is not what you actually need.

英文:

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

using namespace std::string_view_literals;

constexpr auto MaxIndentView = &quot;                                            &quot;sv;

constexpr std::string_view indentView(size_t n)
{
    if (n * 4 &gt; MaxIndentView.size()) {
        throw std::invalid_argument{&quot;Max indentation reached&quot;};
    }
    return MaxIndentView.substr(0, n * 4);
}

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:

确定