/** A compile-time format string. */
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, detail::error_handler,
remove_cvref_t<Args>...>;
detail::parse_format_string<true>(str_, checker(s, {}));
}
#else
detail::check_format_string<Args...>(s);
#endif
}
basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
FMT_INLINE operator basic_string_view<Char>() const { return str_; }
};
把干扰的代码都修剪完,就变成了:
就是里面有一个basic_string_view类型的成员变量,其他的都是编译期的检查
/** A compile-time format string. */
template <typename Char, typename... Args> class basic_format_string {
private:
basic_string_view<Char> str_;
public:
template <typename S>
basic_format_string(const S& s) : str_(s) {
}
basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
operator basic_string_view<Char>() const { return str_; }
};
临时修改一下,看static_assert会报什么错误:
static_assert(
detail::count<
(std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
std::is_reference<Args>::value)...>() != 0, //原来这个地方是==0,临时改一下看看效果
"passing views as lvalues is disallowed");
果然就把信息给打印出来了。而且还给了其他信息。
basic_format_string构造函数用enable_if做了筛选,如果变量类型不能被转换成basic_string_view,那么这个构造函数就不能使用。因为这个类里面有个成员变量是basic_string_view<Char> str_;,如果不能转换成功,那么就无法赋值给这个成员变量。
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) {
}