【问题标题】:Keeping consteval-ness of function arguments保持函数参数的 consteval-ness
【发布时间】:2023-03-14 01:16:01
【问题描述】:

我正在使用整洁的 fmt 库,在其版本 8 中,如果编译器支持相关功能,则会对其格式字符串进行编译时检查。

在某个时候,我想编写以下代码:

throw my_exception("error: {}", 123);

可悲的是,幼稚的实现:

struct my_exception : std::runtime_error {
  template<typename... Args>
  my_exception(Args&&... args)
    : std::runtime_error{fmt::format(std::forward<Args>(args)...)} 
  { }
};

失败,因为这失去了字符串文字参数的“consteval-ness”,这是fmt::format 所要求的。 目前,我选择了以下内容:

template<std::size_t N>
struct literal {
  constexpr literal(const char (&str)[N]) noexcept {
    std::copy_n(str, N, this->str);
  }

  char str[N];
};

template<literal lit>
struct exception : std::runtime_error {
  template<typename... Args>
  exception(Args&&... args)
    : std::runtime_error{fmt::format(lit.str, std::forward<Args>(args)...)}
  {

  }
};

被称为

throw my_exception<"foo {}">(123);

如何在保持编译时检查的同时恢复正常的函数调用语法?

【问题讨论】:

  • 我的建议:不要强迫你的例外使用特定的格式库。我喜欢fmt,但你应该将两者分离。 IE。接受一个字符串并在调用站点 throw my_exception("error: {}"_fmt(123)); 执行此操作(我不记得确切的语法)
  • 不,这是应用程序代码,我只是希望它尽可能简单。解耦它真的是一个 YAGNI,我从 2014 年开始就一直在使用 fmt 并且不打算改变(如果我这样做了,我只会对整个代码库应用重构。但我真的怀疑我会去做一些事情这将使用与 fmt 不同的表达式语法)。

标签: c++ c++20 constexpr fmt consteval


【解决方案1】:

在 {fmt} 8.0 及更高版本中,您可以使用 format_string 模板来执行此操作,顾名思义,该模板表示格式字符串 (https://godbolt.org/z/bqvvMMnjG):

struct my_exception : std::runtime_error {
  template <typename... T>
  my_exception(fmt::format_string<T...> fmt, T&&... args)
    : std::runtime_error(fmt::format(fmt, std::forward<T>(args)...)) {}
};

【讨论】:

    猜你喜欢
    • 2020-04-20
    • 2022-01-06
    • 2019-12-05
    • 2011-04-10
    • 1970-01-01
    • 2021-07-23
    • 2021-10-26
    相关资源
    最近更新 更多