模板参数推导在此 fmt 库的 format_string 中如何工作?

问题描述 投票:0回答:1

我在尝试理解

fmt
库时遇到了一些困难。

让我们从

print
函数开始:

fmt::print("Hello, {}", a);

这是

print
的定义:

template <typename... T>
FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
    // Implementation
}

print
函数接受
format_string<T...>
作为参数。所以我们可以在编译时用
T...
做一些事情。

但是如何在编译时推导出

T...
呢?

以下是

format_string
的实现方式(代码取自10.0.0版本)。对于编译时格式字符串,它有一个隐式 constexpr 构造函数,该构造函数采用
string_view
兼容类型作为参数。

template <typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>;

template <typename Char, typename... Args> class basic_format_string {
 private:
  basic_string_view<Char> str_;

 public:
  template <typename S,
            FMT_ENABLE_IF(
                std::is_convertible<const S&, basic_string_view<Char>>::value)>
  FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) {
    static_assert(
        detail::count<
            (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
             std::is_reference<Args>::value)...>() == 0,
        "passing views as lvalues is disallowed");
#ifdef FMT_HAS_CONSTEVAL
    if constexpr (detail::count_named_args<Args...>() ==
                  detail::count_statically_named_args<Args...>()) {
      using checker =
          detail::format_string_checker<Char, remove_cvref_t<Args>...>;
      detail::parse_format_string<true>(str_, checker(s));
    }
#else
    detail::check_format_string<Args...>(s);
#endif
  }
  basic_format_string(runtime_format_string<Char> fmt) : str_(fmt.str) {}

  FMT_INLINE operator basic_string_view<Char>() const { return str_; }
  FMT_INLINE auto get() const -> basic_string_view<Char> { return str_; }
};

但是,我在源代码中并没有找到用户自定义的推导指南之类的东西。那么模板类

Args...
的类型参数
basic_format_string
是如何推导出来的呢?

c++ c++20 metaprogramming fmt
1个回答
1
投票

扩展别名

format_string
给你

template <typename... T>
FMT_INLINE void print(basic_format_string<char, type_identity_t<T>...> fmt, T&&... args) {
    // Implementation
}

type_identity_t<T>
也是
type_identity<T>::type
的别名:

template <typename... T>
FMT_INLINE void print(basic_format_string<char, type_identity<T>::type...> fmt, T&&... args) {
    // Implementation
}

现在,在第一个函数参数中,模板参数

T
仅出现在嵌套名称说明符的左侧,这使其成为非推导上下文,这意味着函数参数将不会用于推导
 T

所以,第一个函数形参不参与模板实参推导。相反,

T
仅从其他函数参数推导而来,即
T...
只是从
T&&... args
转发参考包推导出来的模板参数。

© www.soinside.com 2019 - 2024. All rights reserved.