为什么使用带有variadic模板参数的struct会同时进行两个模板实例化?

时间:2014-06-15 13:08:09

标签: c++ templates c++11 variadic-templates template-meta-programming

我想知道为什么这个程序没有按预期工作。

#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>

它有两个选择,按分辨率规则,它选择模板的第二个特化。

然后在:

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

C变为std::listT变为intArgs变为empty

然后我们从

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

std::integral_constant的第二个变量变为1 + prank<Args...>prank<Args...>本身将使用空Arguments包调用第一个恶作剧的结构,并且在继承该结构的std::integral_constant值成员后变为9 。

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

但似乎prank<Args...>同时制作和使用2个结构! (struct prank<C<T,Args...>>struct prank

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

1 个答案:

答案 0 :(得分:3)

简介

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

但这是不正确的,因为std::listint后面有一个default-template参数,即分配器: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>
  4. 总收益率?的 11