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-leng
As far as I understand the error is reported because the compiler sees the declaration of the template class as a class with at least 3 arguments followed by the optional ones. Since you try to refer to it with 2 arguments followed by the expansion list, it gets confused and issues this error. In order to make it compile correctly you just need to first declare the template like this:
template <int N, typename TPack, typename... Others>
struct TypePackFirstN;
And after that the recursion step definition has to be restated as a template specialization. (this does the trick with 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;
};
What version of GCC are you using? According to this GCC status page, GCC 4.4 should support it.
Testing with GCC 4.4.2, I get similar error.
The wording of the error message seems to imply that the code should work according the C++0x standard, but that GCC doesn't support it yet. Or perhaps it is a compiler bug?
This is correct, GCC understands the code but cannot yet spit out GIMPLE for it.
As for what causes the error, it's the extension of template variable list to another template's list of variables.
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;
}
I tested this with gcc 4.4.1
deft_code's answer is correct. I'm posting this just in case this it's helpful seeing a side-by-side comparison of broken versus fixed code.
I'll take the code sample from the following question someone posted that was duplicated to this one and is now closed: Is ther a good workaround for GCC's "sorry, unimplemented: cannot expand ‘NEXT ...’ into a fixed-length argument list" error?
#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;
}
This, when compiled, gives:
g++ -std=c++11 -o test test.cc
test.cc:5:50: sorry, unimplemented: cannot expand âNEXT ...â into a fixed-length argument list
But this works (I added comments where code was changed):
#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;
}
Note what was done in this three line change marked by the comments: what was originally the first template was made a specialized template of the newly added variadic template.