可变参数模板的GCC错误:"抱歉,未实现:无法将'标识符...'扩展为固定长度的参数列表"

Den*_*nis 37 c++ templates g++ metaprogramming c++11

在GCC上用C++ 11进行可变参数模板编程时,偶尔会出现一个错误,上面写着"抱歉,未实现:不能将'Identifier ...'扩展到固定长度的列表中." 如果我删除代码中的"...",那么我会得到一个不同的错误:"错误:参数包没有用'...'扩展".

因此,如果我有"...",GCC会调用该错误,如果我取出"......",GCC也会调用该错误.

我能够处理这个问题的唯一方法是使用不同的方法从头开始完全重写模板元程序,并且(幸运的是)我最终提出了不会导致错误的代码.但我真的很想知道我做错了什么.尽管使用谷歌搜索,尽管进行了大量实验,但我无法确定在产生此错误的可变参数模板代码与没有错误的代码之间做出不同的反应.

错误消息的措辞似乎暗示代码应该按照C++ 11标准工作,但GCC还不支持它.或者它可能是一个编译器错误?

这是产生错误的一些代码.注意:我不需要您为我编写正确的实现,而只是指出导致此特定错误的代码是什么

// Used as a container for a set of types.
template <typename... Types> struct TypePack
{
    // Given a TypePack<T1, T2, T3> and T=T4, returns TypePack<T1, T2, T3, T4>
    template <typename T>
    struct Add
    {
        typedef TypePack<Types..., T> type;
    };
};

// Takes the set (First, Others...) and, while N > 0, adds (First) to TPack.
// TPack is a TypePack containing between 0 and N-1 types.
template <int N, typename TPack, typename First, typename... Others>
struct TypePackFirstN
{
    // sorry, unimplemented: cannot expand ‘Others ...’ into a fixed-length argument list
    typedef typename TypePackFirstN<N-1, typename TPack::template Add<First>::type, Others...>::type type;
};

// The stop condition for TypePackFirstN:  when N is 0, return the TypePack that has been built up.
template <typename TPack, typename... Others>
struct TypePackFirstN<0, TPack, Others...> //sorry, unimplemented: cannot expand ‘Others ...’ into a fixed-length argument list
{
    typedef TPack type;
};
Run Code Online (Sandbox Code Playgroud)

编辑: 我注意到,虽然看起来像部分模板实例化会导致错误:

template <typename... T>
struct SomeStruct<1, 2, 3, T...> {};
Run Code Online (Sandbox Code Playgroud)

重写它,因为这不会产生错误:

template <typename... T>
struct SomeStruct<1, 2, 3, TypePack<T...>> {};
Run Code Online (Sandbox Code Playgroud)

看来你可以将部分特化的参数声明为可变参数; 即这条线是好的:

template <typename... T>
Run Code Online (Sandbox Code Playgroud)

但是您无法在专业化中实际使用这些参数包,即此部分不正常:

SomeStruct<1, 2, 3, T...>
Run Code Online (Sandbox Code Playgroud)

事实上,如果你将包装在其他类型中,你可以使它工作,例如:

SomeStruct<1, 2, 3, TypePack<T...>>
Run Code Online (Sandbox Code Playgroud)

对我来说意味着可变参数声明为部分模板特化是成功的,你不能直接使用它.谁能证实这一点?

def*_*ode 48

有一个技巧可以让它与gcc一起使用.该功能尚未完全实现,但您可以构造代码以避免未实现的部分.手动将可变参数模板扩展到参数列表将不起作用.但模板专业化可以为您做到这一点.

template< char head, char ... rest >
struct head_broken
{
   static const char value = head;
};

template< char ... all >
struct head_works; // make the compiler hapy

template< char head, char ... rest >
struct head_works<head,rest...> // specialization
{
   static const char value = head;
};

template<char ... all >
struct do_head
{
   static const char head = head_works<all...>::value;
   //Sorry, unimplemented: cannot expand 'all...' into a fixed-length arugment list
   //static const char head = head_broken<all...>::value;
};

int main
{
   std::cout << head_works<'a','b','c','d'>::value << std::endl;
   std::cout << head_broken<'a','b','c','d'>::value << std::endl;
   std::cout << do_head<'a','b','c','d'>::head << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我用gcc 4.4.1测试了这个