可变模板的GCC错误:“抱歉,未实现:不能将'标识符'扩展成固定长度的参数列表” [英] GCC error with variadic templates: "Sorry, unimplemented: cannot expand 'Identifier...' into a fixed-length argument list"
问题描述
在GCC上使用C ++ 11进行可变模板编程时,偶尔会出现一个错误,对不起,未实现:无法将'Identifier ...'扩展成一个固定长度的列表。如果我删除代码中的...,然后我得到一个不同的错误:错误:参数包不扩展与'...'。
While doing variadic template programming in C++11 on GCC, once in a while I get an error that says "Sorry, unimplemented: cannot expand 'Identifier...' into a fixed-length arugment list." If I remove the "..." in the code then I get a different error: "error: parameter packs not expanded with '...'".
如果我有...,GCC调用一个错误,如果我把...出来,GCC调用一个错误。
So if I have the "..." in, GCC calls that an error, and if I take the "..." out, GCC calls that an error too.
我唯一能够处理这一点的方法是使用不同的方法从头完全重写模板元程序,和(运气)我最终提出了不会导致错误的代码。但我真的想知道我做错了什么。尽管Googling为它,尽管多的实验,我不能确定是什么,我做不同的可变模板代码之间产生这个错误,和代码没有错误。
The only way I have been able to deal with this is to completely rewrite the template metaprogram from scratch using a different approach, and (with luck) I eventually come up with code that doesn't cause the error. But I would really like to know what I was doing wrong. Despite Googling for it and despite much experimentation, I can't pin down what it is that I'm doing differently between variadic template code that does produce this error, and code that does not have the error.
错误消息的措辞似乎意味着代码应该根据C ++ 11标准工作,但GCC不支持它。或者是一个编译器错误?
The wording of the error message seems to imply that the code should work according the C++11 standard, but that GCC doesn't support it yet. Or perhaps it is a compiler bug?
这里是一些产生错误的代码。注意:我不需要你为我写一个正确的实现,而只是指出我的代码是什么导致这个具体的错误
Here's some code that produces the error. Note: I don't need you to write a correct implementation for me, but rather just to point out what is about my code that is causing this specific error
// 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;
};
EDIT:我注意到, like does incur the error:
I've noticed that while a partial template instantiation that looks like does incur the error:
template <typename... T>
struct SomeStruct<1, 2, 3, T...> {};
重写,因为这不会产生错误:
Rewriting it as this does not produce an error:
template <typename... T>
struct SomeStruct<1, 2, 3, TypePack<T...>> {};
您似乎可以将参数声明为偏向特殊化;即这行是OK的:
It seems that you can declare parameters to partial specializations to be variadic; i.e. this line is OK:
template <typename... T>
但实际上不能在专业化中使用部分不正确:
But you cannot actually use those parameter packs in the specialization, i.e. this part is not OK:
SomeStruct<1, 2, 3, T...>
事实上,你可以使它工作,如果你包装在一些其他类型, :
The fact that you can make it work if you wrap the pack in some other type, i.e. like this:
SomeStruct<1, 2, 3, TypePack<T...>>
表示部分模板的可变参数的声明专业化是成功的,你只是不能直接使用它。谁能证实这一点?
to me implies that the declaration of the variadic parameter to a partial template specialization was successful, and you just can't use it directly. Can anyone confirm this?
推荐答案
有一个技巧来使用gcc。该功能尚未完全实现,但您可以构造代码,以避免未实现的部分。将可变参数模板手动扩展为参数列表将不起作用。但是模板专业化可以为你做。
There is a trick to get this to work with gcc. The feature isn't fully implemented yet, but you can structure the code to avoid the unimplemented sections. Manually expanding a variadic template into a parameter list won't work. But template specialization can do that for you.
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.1测试了这个。
I tested this with gcc 4.4.1
这篇关于可变模板的GCC错误:“抱歉,未实现:不能将'标识符'扩展成固定长度的参数列表”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!