参数包参数消耗

时间:2012-09-16 10:35:57

标签: c++ variadic-templates

可以获取参数包的 first 元素,如this

template <typename... Elements>
struct type_list
{
};

template <typename TypeList>
struct type_list_first_element
{
};

template <typename FirstElement, typename... OtherElements>
struct type_list_first_element<type_list<FirstElement, OtherElements...>>
{
    typedef FirstElement type;
};

int main()
{
   typedef type_list<int, float, char> list;
   typedef type_list_first_element<list>::type element;
   return 0;
}

但不可能像<{3}}那样获得 last 元素

template <typename... Elements>
struct type_list
{
};

template <typename TypeList>
struct type_list_last_element
{
};

template <typename LastElement, typename... OtherElements>
struct type_list_last_element<type_list<OtherElements..., LastElement>>
{
    typedef LastElement type;
};

int main()
{
   typedef type_list<int, float, char> list;
   typedef type_list_last_element<list>::type element;
   return 0;
}

与gcc 4.7.1抱怨:

  

错误:'struct type_list_last_element&lt; type_list&lt; int,float,char&gt;&gt;'中的'type'没有命名类型

标准的哪些段落描述了这种行为?

在我看来,模板参数包是 greedy ,因为它们使用所有匹配的参数,在这种情况下意味着OtherElements消耗所有三个参数({{1} },intfloat)然后char没有任何内容,因此编译失败。我在假设中是否正确?

修改

澄清:我不是问如何从参数包中提取最后一个元素,我知道如何做到这一点。我真正想要的是从背面而不是前面挑选背包,因此每个元素一直到后面的递归都是无效的。事先明确地逆转序列是最明智的选择。

2 个答案:

答案 0 :(得分:4)

相关条款是14.5.5:8结尾处的子弹:

  

14.5.5类模板部分特化[temp.class.spec]

     

8 - 在类模板部分特化的参数列表中,以下限制适用:   [...]

     
      
  • 参数不应包含未展开的参数包。如果参数是包扩展(14.5.3),则它应该是模板参数列表中的最后一个参数。
  •   

答案 1 :(得分:1)

观察:

  1. <first,...>的最后一个元素与<...>的最后一个元素相同 如果只有...不为空。
  2. 一个元素列表<elem>的最后一个元素是elem
  3. 所以你必须使用tail模板递归地执行它:

    递归:

    template <typename TypeList>
    struct type_list_last_element;
    
    template <typename FirstElement, typename... OtherElements>
    struct type_list_last_element<type_list<FirstElement, OtherElements...>>
    {
        typedef typename type_list_last_element<type_list<OtherElements...>>::type type;
    };
    

    尾:

    template <typename LastElement>
    struct type_list_last_element<type_list<LastElement>>
    {
        typedef LastElement type;
    };
    

    [更新] 和用法:

    int main()
    {
       typedef type_list<int, float, char> list;
       typedef type_list_last_element<list>::type last;
       return 0;
    }
    

    [END UPDATE]

    请参阅ideone