GCC错误与可变参数模板:“对不起,未实现:不能扩展'标识符…'到一个固定长度的参数列表”
在GCC的C ++ 11中进行可变模板编程时,偶尔会遇到一个错误,提示“对不起,未实现:无法将”标识符…“扩展为固定长度的列表。 如果我删除代码中的“…”,那么我会得到一个不同的错误:“错误:参数包不能用'…'扩展。
所以如果我有“…”,GCC会调用这个错误,如果我把“…”取出,GCC也会调用这个错误。
我已经能够处理这个问题的唯一方法是从头开始用一种不同的方法完全重写模板元程序,并且(幸运的是)我最终得到了不会导致错误的代码。 但我真的想知道我做错了什么。 尽pipe谷歌search,尽pipe进行了大量的实验,我不能确定我做了不同的模板代码之间产生这种错误,和没有错误的代码。
错误信息的措辞似乎意味着代码应该按照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; };
编辑:我注意到,虽然看起来像部分模板实例会产生错误:
template <typename... T> struct SomeStruct<1, 2, 3, T...> {};
重写它不会产生错误:
template <typename... T> struct SomeStruct<1, 2, 3, TypePack<T...>> {};
看来,你可以声明参数部分专业化是可变的; 即这一行是确定的:
template <typename... T>
但是你不能在专业化中使用这些参数包,也就是说这个部分是不正确的:
SomeStruct<1, 2, 3, T...>
事实上,你可以使它工作,如果你包装在一些其他types的包,即这样的:
SomeStruct<1, 2, 3, TypePack<T...>>
对我来说意味着可变参数对部分模板专门化的声明是成功的,你不能直接使用它。 任何人都可以确认吗?
有一个技巧,让这与gcc工作。 该function尚未完全实现,但您可以构造代码以避免未实现的部分。 手动将可变参数模板扩展到参数列表中将不起作用。 但模板专业化可以为你做到这一点。
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; }
我用gcc 4.4.1testing了这个
据我了解,错误报告是因为编译器将模板类的声明看作是一个具有至less3个参数的类,然后是可选的参数。 既然你试着用2个参数跟着扩展列表来引用它,它会变得困惑并且发出这个错误。 为了使它正确地编译,你只需要首先声明这样的模板:
template <int N, typename TPack, typename... Others> struct TypePackFirstN;
之后,recursion步骤定义必须重新作为模板专业化。 (这与gcc 4.5.0 20100404的技巧)。
// 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<N, TPack, First, Others...> { // Error "sorry, unimplemented: cannot expand 'Others ...' into a fixed-length argument list" should be now gone 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...> // Error "sorry, unimplemented: cannot expand 'Others ...' into a fixed-length argument list" should be now gone { typedef TPack type; };
你使用的是什么版本的GCC? 根据这个GCC状态页面 ,GCC 4.4应该支持它。
用GCC 4.4.2testing,我得到类似的错误。
错误消息的措辞似乎意味着代码应该按照C ++ 0x标准工作,但GCC不支持它。 或者,也许这是一个编译器错误?
这是正确的,海湾合作委员会了解代码,但还不能吐出GIMPLE。
至于导致错误的原因,是模板variables列表扩展到另一个模板的variables列表。
deft_code的回答是正确的。 我发布这个只是为了防止这种情况有助于看到破损与固定代码的并行比较。
我将从下面的问题的代码示例中发布的人被复制到这个,现在是closures的: 对于GCC的“对不起,未实现:不能展开'NEXT …'是一个很好的解决方法成固定长度的参数列表“错误?
#include <iostream> template <int FIRST, int... NEXT> struct Test { static const int VALUE = FIRST + Test<NEXT...>::VALUE; }; template <int FIRST> struct Test<FIRST> { static const int VALUE = FIRST; }; int main() { std::cout << Test<1, 2, 3>::VALUE << std::endl; // print "6" return 0; }
这个在编译时会给出:
g++ -std=c++11 -o test test.cc test.cc:5:50: sorry, unimplemented: cannot expand âNEXT ...â into a fixed-length argument list
但是这个工作(我在代码被改变的地方添加了注释):
#include <iostream> template <int ... ALL> // Adeed struct Test; // Added template <int FIRST, int... NEXT> struct Test<FIRST, NEXT...> { // Note: specialized with <FIRST, NEXT...> static const int VALUE = FIRST + Test<NEXT...>::VALUE; }; template <int FIRST> struct Test<FIRST> { static const int VALUE = FIRST; }; int main() { std::cout << Test<1, 2, 3>::VALUE << std::endl; // print "6" return 0; }
注意这三条线所做的修改是由注释标记的:最初的第一个模板是由新增加的可变模板的专门模板制成的。