为什么使用带可变模板参数的结构体同时实例化两个模板

Why using struct with variadic template parameter makes two template instantiation at the same time?

本文关键字:实例化 两个 为什么 参数 结构体      更新时间:2023-10-16

我想知道为什么这个程序不像预期的那样工作。

#include <iostream>
#include <utility>
#include <list>
template <typename... Args>
struct prank
        : std::integral_constant<std::size_t, 9> {};
template <template <typename...> class C,typename T, typename ...Args>
struct prank<C<T,Args...>>
        : std::integral_constant<
        std::size_t,
        1+ prank<Args...>::value> {};
int main()
{
    using T = std::list<int>;
    std::cout << prank<T>::value << "n";
}

ideone

输出是11,但它应该是10。

让我解释一下为什么:

main()中我们称prank<T>std::list<int>

它有两个选择,根据解析规则,它选择模板的第二个专门化。

Then in:

  template <template <typename...> class C,typename T, typename ...Args>
    struct prank<C<T,Args...>>

C变为std::list, T变为int, Args变为empty

然后从

继承
std::integral_constant<
            std::size_t,
            1+ prank<Args...>::value>

std::integral_constant的第二个变量变成1 + prank<Args...>, prank<Args...>自己调用第一个恶作剧的结构体,带空参数包,继承std::integral_constant后该结构体的值成员变成9。

所以1+ prank<Args...>::value应该变成1+9=10而不是11 !

prank<Args...>似乎同时制造和使用2个结构体!(struct prank<C<T,Args...>> and struct prank)

这是一个bug还是我犯了一个错误?(我使用gcc 4.8.1)

简介

问题是您假设std::list只有一个模板参数,导致prank<std::list<int>>的实例化,这将导致prank<int>的实例化。

然而这是不正确的,这是因为std::listint之后有一个默认模板参数,即分配器:std::allocator<int>

template<class T, class Allocator = std::allocator<T>>
class std::list;
std::list<int> => std::list<int, std::allocator<int>>

解释
template <typename... Args>
/* (A) -> */ struct prank : std::integral_constant<std::size_t, 9> {};
template <template <typename...> class C,typename T, typename ...Args>
/* (B) -> */ struct prank<C<T,Args...>>
        : std::integral_constant<std::size_t, 1+ prank<Args...>::value> {};

实例化,顺序为:

  1. (b) prank<std::list<int, std::allocator<int>>>
  2. (b) prank<std::allocator<int>>
  3. (a) prank<int>

总产值?11 .