I recently started trying out various template tricks. In this case I tried to implement a class holding a sequence of numbers supplied by a variadic template utilizing a parameter pack.
However, I run into some problems that do not occur on the compiler I use (Intel C++ 14), but on others like CLang or GCC. I am therefore quite confused about which compiler is "more on point" in its interpretation of the standard.
Here is my code:
#include <iostream>
using namespace std;
template< size_t... Sequence >
class CSequence
{
public:
CSequence()
{
this->generate< Sequence... >();
this->out();
}
private:
// Recursion end
template< size_t N >
void generate(size_t sz)
{
// Create array
this->m_Array = new size_t[sz+1];
this->m_Len = sz+1;
this->m_Array[sz] = N;
}
// Recursion segment
template< size_t N, size_t... Ns >
void generate(size_t sz)
{
generate<Ns...>(sz+1);
this->m_Array[sz] = N;
}
// Recursion start
template< size_t... Ns >
void generate()
{
generate<Ns...>(0);
}
void out()
{
for(int i = 0; i < this->m_Len; i++)
{
std::cout << this->m_Array[i] << " ";
}
std::cout << std::endl;
}
private:
size_t* m_Array;
size_t m_Len;
};
int main()
{
CSequence< 1, 2, 3, 4, 5, 6, 7, 8 > a;
std::getchar();
}
This compiles fine on my end using Intel C++ 14 and produces the result I would expect:
1 2 3 4 5 6 7 8
But on the newest versions of both CLang and GCC it fails to compile:
Now, I can actually understand the reason for the failure: As parameter packs can contain zero elements, the exemplary call
generate< 8 >( size_t );
may be resolved both as
generate< N = 8, Ns = <> > ( size_t )
and as
generate< N = 8 > ( size_t )
thus resulting in an unresolvable ambiguity. But the fact that it compiles on my end and actually gives the expected result makes me wonder:
Note that this piece of code is to be considered as some kind of experiment, so I'm happy with both alternative strategies and fixes for this particular piece of code.
This doesn't require a recursive implementation at all.
template< size_t... Ns >
void generate()
{
m_Len = sizeof...(Ns);
m_Array = new size_t[m_Len] { Ns... };
}
You can also dispense with the dynamic allocation and make m_Array
an actual array, and initialize it with a NSDMI:
size_t m_Array[sizeof...(Sequence)] = {Sequence... };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With