可变参数模板参数的 C++ 约束

标签 c++ template-meta-programming type-deduction

我在 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 做那个时髦的事情。

我为什么需要这个?

最佳答案

参见 https://en.cppreference.com/w/cpp/language/template_argument_deduction#Implicit_conversions :

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

FormatString/IdentityType 如何改变事物? IdentityType 抑制了 const char[N] 的模板参数推导,现在该字符串用作 UnconstrainedFormatString<...> 的构造函数参数em>.

您可以在此处了解更多详细信息: https://humanreadablemag.com/issues/0/articles/how-to-avoid-template-type-deduction-in-c

当您仅使用 UnconstrainedFormatString 时,编译器会尝试从 const char [N] 中扣除 UnconstrainedFormatString 并失败,因为对于模板它“doesn我不知道”存在从 const char[N]UnconstrainedFormatString 的转换。

你可以很容易地检查

println(UnconstrainedFormatString<int, int, int>("test"), 1, 2, 3);

因为这里不需要转换,所以它也可以。

关于可变参数模板参数的 C++ 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68866788/

相关文章:

c++ - 如何直接从内存编译执行?

c++ - 如何创建一个可以使用 Boost 和 OpenCV 读取文件夹中所有图像的程序?

c++ - 检查我们是否有 const 类型

c# - C++ 后台代码分析器,如 C# 的 Resharper?

c++ - 获取对模板参数给定类型对象的虚拟引用

c++ - 元编程 : using a const array

c++ - 有没有办法一致地对类型模板参数进行排序?

c++ - 推断声明的类型

c++ - 使用模板模板参数时模板参数推导失败

c++ - 1.6 的 SFML pollEvent(等效项)