RnM*_*Mss 1 c++ metaprogramming c++20 fmt
我在尝试理解该fmt库时遇到了一些困难。
我们从print函数开始:
fmt::print("Hello, {}", a);
Run Code Online (Sandbox Code Playgroud)
这是 的定义print:
template <typename... T>
FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
// Implementation
}
Run Code Online (Sandbox Code Playgroud)
该print函数采用 aformat_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_; }
};
Run Code Online (Sandbox Code Playgroud)
但是,我在源代码中没有找到用户定义的推导指南或类似的内容。那么 Args...模板类的类型参数是如何推导的呢basic_format_string?
扩展别名format_string给你
template <typename... T>
FMT_INLINE void print(basic_format_string<char, type_identity_t<T>...> fmt, T&&... args) {
// Implementation
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
现在,在第一个函数参数中,模板参数T仅出现在嵌套名称说明符的左侧,这使其成为非推导上下文,这意味着该函数参数将不会用于推导T。
因此,第一个函数参数不参与模板实参推导。相反,T仅从其他函数参数推导,即T...仅从T&&... args转发参考包推导模板参数。