实例化可变参数函数模板时出现奇怪的编译错误

冰1357

我们先介绍一个表示参数包的辅助类型:

template<typename... T> struct Pack { };

现在,这是具有奇怪行为的函数:

template<typename... TT, typename T>
void f(Pack<TT...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>);

std::type_identity_t此处用于禁用对最后两个参数的推导,以防引入任何歧义。

首先,我试着这样称呼它:

f(Pack<int>{}, Pack<int>{}, 5, 5);

GCC 引发错误并给出以下解释:

<source>:12:6: note:   candidate expects 3 arguments, 4 provided
   12 |     f(Pack<int>{}, Pack<int>{}, 5, 5);
      |     ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这不是我预期的那种错误,我认为扣除会导致T = intand TT... = int但是,好吧,让我们按照笔记所说的做,并少提供一个论点:

f(Pack<int>{}, Pack<int>{}, 5);

它仍然给出一个错误,但这次是:

<source>:12:6: error: too few arguments to function 'void f(Pack<TT ...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>) [with TT = {int}; T = int; std::type_identity_t<T> = int]'
   10 |     f(Pack<int>{}, Pack<int>{}, 5);
      |     ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

现在他们太少了。另请注意,此错误消息证实了我对推导的T和的假设TT...

此时我切换到 Clang 以查看它是否会编译此代码,但上述两个调用f(带有 3 个和 4 个参数)都会导致相同的错误,并注意:

<source>:8:6: note: candidate template ignored: deduced packs of different lengths for parameter 'TT' (<int> vs. <>)
void f(Pack<TT...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>);
     ^

我还尝试使用 MSVC 编译代码,它确实编译没有错误。

到底是怎么回事?有什么东西使这段代码无效吗?由于奇怪的错误消息,它是编译器错误吗?

东风

std::type_identity<TT>...在评论中提到作为从参数推导中删除第三个函数参数(这是一个包)的一种方法,但这没有效果,因为没有出现在参数列表末尾的函数参数包位于非无论如何推断上下文;根据[temp.deduct.type]/5.7

/5 未推断的上下文是:

  • [...]
  • /5.7 不出现在参数声明列表末尾的函数参数包。

那么为什么不能从第一个函数参数(Pack<TT...>)中明确推导出参数包呢?这对于 C++ 开发人员来说可能是有意义的,但是它可能最终成为实现者的实现质量问题,因为它将开始将模板参数推导与重载解析混合在一起。这将需要两次模板参数推导,其中首先明确推导出一个参数包,然后从一个函数参数中推导出,然后使用结果修改同一函数的参数列表(以扩展其他不可推导的参数包),然后返回到修改后的函数模板的模板参数推导。这不是模板参数推导在其他任何地方的工作方式,可能仅仅是由于实现的质量。

[temp.deduct.call]/1确实提到从未推断出这样的包(强调我的):

[...]当函数参数包出现在非推导上下文([temp.deduct.type])中时,永远不会推导该包的类型。

可以争论这是否故意拒绝可以从其他任何地方推断出来的包。如果是这样,则 OP 的程序确实格式错误,但是编译器的错误消息对于将其诊断为根本原因(如果是的话)并没有多大帮助。似乎编译器可能依赖 [temp.deduct.call]/1 将不可演绎的模板参数包实际推导出为空包。


我们最终可能会注意到 [temp.deduct.call]/1 支持使用显式模板参数,因为这不是推导:

#include <type_traits>

template<typename... T> struct Pack { };

// Note the swap of template argument positions
// to allow explicitly providing template arguments.
template<typename T, typename... TT>
void f(Pack<TT...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>) {}

int main() {
    f<int, int, int>(Pack<int, int>{}, Pack<int>{}, 1, 2, 3);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

未实例化的函数模板中的编译时错误

可变参数模板函数的显式实例化

可变参数模板错误:“实例化中”(gcc 9.2)

如何使用此模板使用可变参数模板变量来解决我的编译错误

将可变参数传递给模板函数时的编译错误

实例化模板化std :: function时的编译错误

可变参数模板代码中的 GCC 与 MSVC 编译错误

可变参数模板方法和std :: function-编译错误

可变参数模板递归返回类型推导编译错误

如何检查类型是否从模板函数中的某个可变参数模板类实例化?

可变参数模板类参数容器实例化

使用参数化构造函数时缺少编译错误

在可变参数模板的实例化过程中函数不可见

使用不同的枚举参数时,VC ++函数模板实例化错误C2664

在实例化函数模板时省略模板类型参数是否合法?

在C ++中使用带有参数类型检查的可变参数模板在编译时获取函数的参数数量

专业化可变参数模板成员函数

可变参数模板成员函数的部分专业化

无法编译包含“ if constexpr”的函数模板实例化

内部编译器错误:gcc中的分段错误。发送可变参数模板到结构时

Boost状态图-使用状态图作为模板参数时出现编译错误

修复使用非标量类型实例化模板时的编译错误

使用 Lombok 和 IntelliJ 时出现奇怪的编译错误

可变参数可变参数模板模板专业化错误

如何使用折叠表达式实例化可变参数模板函数中的每种类型?

与模板实例化有关的编译错误

在坐标类型上对类进行模板化并使用Boost Geometry库时出现编译错误

不使用模板[opencv]时出现编译错误

在带有Angular的函数参数中使用联合类型时出现编译错误