可变参数模板的 GCC 错误:“抱歉,未实现:无法将“标识符..."扩展为固定长度的参数列表"
在 GCC 上使用 C++11 进行可变参数模板编程时,偶尔会收到一条错误消息,提示抱歉,未实现:无法将 '标识符...' 扩展为固定长度的参数列表."如果我删除代码中的...",我会得到一个不同的错误:错误:参数包没有用'...'扩展".
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.
我能够处理这个问题的唯一方法是使用不同的方法从头开始完全重写模板元程序,并且(幸运的是)我最终想出了不会导致错误的代码.但我真的很想知道我做错了什么.尽管谷歌搜索并进行了大量实验,但我无法确定我在产生此错误的可变参数模板代码和没有错误的代码之间所做的不同.
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;
};
我注意到,虽然看起来像的部分模板实例化确实会导致错误:
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...> {};
重写它不会产生错误:
template <typename... T>
struct SomeStruct<1, 2, 3, TypePack<T...>> {};
似乎您可以声明部分特化的参数是可变参数的;即这条线没问题:
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
相关文章