如果在可推导类型上存在替换,则可变参数模板类型推导会使编译器崩溃

Nik*_*zev 8 c++ language-lawyer variadic-templates template-argument-deduction c++14

我想我在所有编译器中遇到了模板类型演绎错误,但在报告之前我想确定我没有错过任何东西.

考虑一个例子:

#include <utility>

template <std::size_t... I, typename... T>
void foo(std::index_sequence<I...>, decltype(I)..., T...) {}

int main()
{
    foo(std::make_index_sequence<3>{}, 1, 2, 3, 4, 5);
}
Run Code Online (Sandbox Code Playgroud)

decltype(I) 这里用来缩短MWE.

  • GCC: error: too few arguments to function
  • Clang崩溃了 error: no matching function for call to 'foo'
  • MSVC崩溃了 error C3543: 'unknown-type': does not contain a parameter pack

我不明白为什么它没有扣除T,特别是因为它可以用varargs替换参数包(除了MSVC,它再次有ICE).

template <std::size_t... I>
void foo(std::index_sequence<I...>, decltype(I)..., ...) {}
Run Code Online (Sandbox Code Playgroud)

还有很多其他方法可以制作我想要的东西,但这是最短的方式,我没有看到它应该失败的任何理由.

更新:在deducible上替换的已知有效示例是:

template <typename T>
struct type_identity
{ using type = T; };

template <typename T, typename... U>
void foo(T, typename type_identity<T>::type, U...) {}

int main()
{
    foo(1, 2, 3, 4, 5);
}
Run Code Online (Sandbox Code Playgroud)

更新#2原始示例的修改版本不会崩溃Clang,但有关错误的说明很奇怪note: candidate template ignored: deduced conflicting types for parameter 'T' (<int, int, int> vs. <>)

#include <utility>

template <typename T>
struct type_identity
{ using type = T; };

template <typename...>
struct type_pack {};

template <typename... T, typename... U>
void foo(type_pack<T...>, typename type_identity<T>::type..., U...) {}

int main()
{
    foo(type_pack<int, int, int>{}, 1, 2, 3, 4, 5);
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 5

我认为你的代码在标准中是不正确的,但可以提出一个论点,即应该改变标准以使其格式良好.

模板参数推导过程在标准中描述如下:

  1. 明确指定的模板参数被替换为函数模板声明([temp.deduct]/2-5).
  2. 推导出在参数类型列表中推导出的上下文中出现的剩余模板参数([temp.deduct.call]).
  3. 推导出的模板参数以及具有默认模板参数的模板参数将替换为函数声明[temp.deduct.call]/10.这是扣除过程的结束,然后是重载解决.

因此,程序是替代 - 扣除 - 替代 ; 在替换推导出的论点后,没有后续的推论.[temp.deduct]/6提供了对此视图的进一步支持:

在模板参数推导过程中的某些点,有必要采用一个使用模板参数的函数类型,并用相应的模板参数替换这些模板参数.当任何显式指定的模板参数被替换为函数类型时,这在模板参数推导的开始处完成,并且当替换从默认参数推导或获得的任何模板参数时,再次在模板参数推断的结尾处完成.

你的例子是不正确的,因为它需要扣除然后替换然后扣除:T...除非I...推断和替换,否则不能推断.