c++ 如何省略fmt::格式中的空参数?

qxsslcnc  于 2023-01-15  发布在  其他
关注(0)|答案(2)|浏览(155)

有没有办法省略fmt::format函数的参数列表中的空字符串常量("")?
我有下面的代码片段,它给出了所需的输出:

#include <string>
#include <fmt/core.h>

int main( )
{
    const std::string application_layer_text_head { fmt::format( "{:*<5}[Application Layer]{:*<51}\n\n", "", "" ) };
    fmt::print( "{}", application_layer_text_head );
}

输出:

*****[Application Layer]***************************************************

所以不要写这个:fmt::format( "{:*<5}[Application Layer]{:*<51}\n\n", "", "" )我们可以删除空的文字量并写为:我试过了,但是编译失败了。这两个字面值没有任何用处,所以我想找到一种不写它们的方法。
澄清一下,我只想在开始时有5个*,然后是[Application Layer],然后是51个*,然后是2个\n

7dl7o3gd

7dl7o3gd1#

格式化标记用于使用用户提供的数据来格式化字符串。格式化中的特殊语法可以调整这种格式化的工作方式,甚至可以插入字符等。但这种功能是对基本操作的补充:获取用户提供的对象并将其注入字符串。
因此,format没有一种机制允许您避免提供用户提供的数据,而用户提供的数据正是format存在的全部原因。
还应该注意的是,格式说明符中:后面的文本的含义是根据要格式化的对象的类型定义的。“〈5”表示“使用''字符填充空格以对齐5个字符”,这仅仅是因为 * 您为该特定格式参数提供了一个字符串。因此,format不仅没有提供这样做的方法,它在功能上 cannot。你必须告诉它使用的是什么类型,因为这是处理“〈5”含义的一个组成部分。

du7egjpx

du7egjpx2#

如前所述,format不能做到这一点,但是您对字符串连接代价高昂的担忧是不必要的;X1 M1 N1 X的重复应用是昂贵的(执行新的分配、复制所有现有数据和新数据、丢弃旧数据,一遍又一遍),但是operator+=append的就地连接成本很低,特别是如果您预先使用reserve(因此,您只需预先分配一次并填充,而不是依靠重新分配中的摊销增长模式来保存成本)。即使没有reserve之前的版本,std::string遵循摊提增长模式,因此重复的原地串联摊提O(1)(每个添加的字符),而不是迄今为止数据大小中的O(n)
从本质上讲,下面的代码应该至少和格式化一样快,尽管代价是执行-reserve之前的代码行以防止重新分配:

#include <string>
#include <string_view>
#include <fmt/core.h>

using namespace std::literals;

int main( )
{
    // Make empty string, and reserve enough space for final form
    auto application_layer_text_head = std::string();
    application_layer_text_head.reserve(5 + "[Application Layer]"sv.size() + 51 + "\n\n"sv.size());

    // append is in-place, returning reference to original string, so it can be chained
    // Using string_view literals to avoid need for any temporary runtime allocated strings,
    // while still allowing append to use known length concatenation to save scanning for NUL
    application_layer_text_head.append(5, '*').append("[Application Layer]"sv).append(51, '*').append("\n\n"sv);
    fmt::print("{}", application_layer_text_head);
}

如果您可以接受一些可能执行重新分配的串联,以及将资源从临时引用移动到实际字符串的final move构造,那么它可以简化为一行代码:

const auto application_layer_text_head = std::move(std::string(5, '*').append("[Application Layer]"sv).append(51, '*').append("\n\n"sv));

或者,考虑到5个星号短到足以键入,则更短/更简单的版本:

const auto application_layer_text_head = std::move("*****[Application Layer]"s.append(51, '*').append("\n\n"sv));

但是,将其保持为两行代码可以避免移动构造,并且稍微安全一些:

auto application_layer_text_head = "*****[Application Layer]"s;
application_layer_text_head.append(51, '*').append("\n\n"sv);

是的,没有一个像一个单独的格式文本那样漂亮,即使有“丑陋的”空占位符,如果你喜欢格式字符串的外观,就像你已经做的那样沿着空占位符。

相关问题