为什么 C++20 格式没有格式字符串的强类型定义?

Why C++20 format has no strong typedef for format string?

C++20 引入了以下 format 函数(语言环境和 wstring_view 版本被忽略,因为它们不影响问题):

template<class... Args>
std::string format(std::string_view fmt, const Args&... args);

这没什么问题,但我想知道为什么没有接受“强类型定义”的重载,比如

template<class... Args>
    std::string format(std::format_string fmt, const Args&... args);

我的猜测是以下部分或全部:

  1. 实施的复杂性增加

  2. 编译时间增加

  3. 代码膨胀

,但我想知道在标准化过程中是否讨论过这个问题。

强 typedef 的目的是防止这种情况发生:

void takes_id(SomeIdType);
takes_id(42); 

format 的要点是让它起作用:

format("User {} owes me {} points.", name, 100);

这是一个字符串文字。要求强类型对用户来说意味着更多的负担,不得不这样写:

format(format_string("User {} owes me {} points."), name, 100);

这不是典型的强类型定义用例的负担,因为您实际上是在 SomeIdType 中进行交易。您将拥有一个为您提供 SomeIdType 的函数,您将存储一个 SomeIdType 类型的成员。基本上,实际转换的数量将是相当少的......所以在调用站点上你只需编写 takes_id(my_id) 并且代码大部分看起来是一样的,增加了安全性。

但是格式化的最常见情况是使用字符串文字,因此需要添加很多注释。

强类型的名义上的好处是抓住用户做这样的事情:

format(name, "User {} owes me {} points.", 100);

甚至:

format(name, 100);

前者似乎不太可能发生。后者当然是可能的,如果第一个参数恰好足够像字符串。但这是一个足以迫使每个人编写更多代码的常见问题吗?我不这么认为。

现在,如果字符串字面值有自己不同于 const char[N] 的类型(我真的希望他们有),那么就可以创建一个可从 std::string_literal 隐式构造的类型,但是需要 显式 std::string_view 构造。如果那是一回事,那么 API 可能会使用它 - 因为在常见情况下这不需要注释,并且不使用字符串文字似乎非常罕见,以至于需要显式转换似乎......好吗?

此外,关于安全问题,问题不在于传递错误类型的字符串,而在于实际上能够在其上下文中验证它的值:

format("User {} owes me {} points.", name);

我们非常希望这个不编译,即使我们在正确的位置提供了格式字符串。它似乎是 possible to do this。但是我们也不需要强大的类型定义,我们只需要知道格式字符串是否是常量表达式的能力。


总而言之,答案是:

but I wonder why is there not an overload that accepts a "strong typedef"

是这需要用户提供更多的调用端注释,同时提供非常小的好处。它只会在最罕见的用途中捕获错误的用途,因此似乎是一个相当糟糕的权衡。