Reputation: 394
I have a class Index
similar to std::integer_sequence
:
template<std::size_t... NValues>
struct Index { };
And I wanna Fill it with sequence N-1, N-2, ..., 2, 1, 0.
template<std::size_t N>
struct MakeIndex
{
private:
template<std::size_t I, std::size_t... NIndexValues>
struct _Make;
public:
using Type = typename _Make<N>::Type;
private:
template<std::size_t I, std::size_t... NIndexValues>
struct _Make
{
using Type = typename _Make<I - 1, NIndexValues..., I - 1>::Type;
};
template<std::size_t... NIndexValues>
struct _Make<0, NIndexValues...>
{
using Type = Index<NIndexValues...>;
};
};
int main()
{
using T = MakeIndex<5>::Type;
}
On clang compiler(3.7.0), it produce
fatal error: recursive template instantiation exceeded maximum depth of 256
It works very well on VS and GCC. Maybe I did something wrong? Or it is compiler bug?
Upvotes: 4
Views: 1195
Reputation: 11317
It looks like a compiler bug, though I'm not certain if the issue lies with clang or with gcc and msvc.
It looks like clang will not use the template specialization when called with 0. (You can add a static assert to make the errors more readable).
The problem you are facing is linked to the using
you have defined. At the moment the compiler is parsing this using, it only knows of a single definition of _Make
, which ain't specialized and somehow in instantiating the template, it only uses this information.
If we add the specialization earlier it does compile.
As GCC doesn't compile without the forward declaration, having the declaration is a requirement for the lookup, so I would guess that GCC is resolving a class which actually ain't declared at that moment, which it most likely shouldn't do.
However, to be sure about the correct behavior, I would suggest just logging a bug. If it ain't a bug in the compiler it is logged on, they will most likely explain why the other is wrong, which you can use to log the second bug.
Upvotes: 1
Reputation: 16334
Looks to me like a clang compiler bug. If you do not use a forward declaration, it also compiles on clang:
template<std::size_t N>
struct MakeIndex
{
private:
template<std::size_t I, std::size_t... NIndexValues>
struct _Make
{
using Type = typename _Make<I - 1, NIndexValues..., I-1>::Type;
};
template<std::size_t... NIndexValues>
struct _Make<0, NIndexValues...>
{
using Type = Index<NIndexValues...>;
};
public:
using Type = typename _Make<N>::Type;
};
Upvotes: 2