【发布时间】:2021-10-22 06:43:47
【问题描述】:
我在SerenityOS project 中偶然发现了这段代码:
template<typename... Parameters>
void dbgln(CheckedFormatString<Parameters...>&& fmtstr, const Parameters&... parameters)
他们正在从 rust 重新实现 println! 的等价物。一个更简单的 printf 版本,您不需要关心参数类型并以这种方式使用:
dbgln("This is a {}", "test");
他们正在对fmtstr 进行一些编译时检查,以确保没有未闭合的大括号并且大括号的数量与参数的数量相匹配。这就是为什么需要对 FormatString 结构进行模板化以在编译时访问参数数量的原因。
但是有一点我不明白。 I wrote 一个 MWE,其代码如下,本质上是重现他们正在做的事情:
#include <stddef.h>
template<typename... Args>
void compiletime_fail(Args...);
template<typename ...Parameters>
struct UnconstrainedFormatString {
template <size_t size>
consteval UnconstrainedFormatString(const char (&buffer)[size]): m_buffer(buffer), m_size(size) {
}
const char *m_buffer { nullptr };
const size_t m_size { 0 };
};
template<typename T>
struct __IdentityType {
using Type = T;
};
template<typename T>
using IdentityType = typename __IdentityType<T>::Type;
template<typename... Args>
using FormatString = UnconstrainedFormatString<IdentityType<Args>...>; // but why?
template<typename ...Parameters>
constexpr void println(FormatString<Parameters...>&& fmtstr, const Parameters& ...parameters) {
}
int main() {
println("this is a test", 1, 2, 3);
}
如果我在println 签名中使用UnconstrainedFormatString,我会从编译器收到此错误:
/cplayground/code.cpp:32:3: error: no matching function for call to 'println'
println("this is a test", 1, 2, 3);
^~~~~~~
/cplayground/code.cpp:28:16: note: candidate template ignored: could not match 'UnconstrainedFormatString<type-parameter-0-0...>' against 'char const[15]'
constexpr void println(UnconstrainedFormatString<Parameters...>&& fmtstr, const Parameters& ...parameters) {
为了编译它,我需要用IdentityType 做这个时髦的事情。
我为什么需要这个?
【问题讨论】:
-
为什么需要 UnconstrainedFormatString 作为模板?如果您将其定义为结构,则使用 UnconstrainedFormatString 一切都会正常工作。你不会把事情复杂化吗?
-
我认为目的是在编译时检查大括号的数量是否与参数的数量相匹配。
-
防止从该论点中扣除。见stackoverflow.com/questions/17433082/…
-
@ecatmur 我想你可能在这里有所收获。但是在我的示例中,不可能有歧义,因为不可能从格式字符串中推断出可变参数的类型。想详细说明一下,也许在答案中?
-
好的,en.cppreference.com/w/cpp/language/… 解释了等同于 std::type_identity 的 IdentityType。但它的使用是为了避免模棱两可的类型推导,这不是这里的情况。错误是不同的。仍然需要了解错误的来源才能全面了解。
标签: c++ template-meta-programming type-deduction