39

I have this code

template<int N, bool C = true>
struct A;

template<int N>
struct A<N, !(N % 5)> {
  /* ... */
};

// should work
A<25> a;

That is, for numbers N that are divisible by 5, the compiler should use the partial specialization. But the compiler won't accept that partial specialization, because the Standard requires it to reject such code where a non-type argument of a partial specialization references a parameter and is not simply a parameter (like, A<N, N> would be valid). But what is the reason of doing so?

Note that I can simply change my code to a more wordy example and it is valid

template<bool> struct wrap;
template<int N, typename = wrap<true> >
struct A;

template<int N>
struct A<N, wrap<!(N % 5)> > {
  /* ... */
};

// should work
A<25> a;

This is fine because it's not a non-type parameter anymore. But what is the reason the spec forbids the more straightforward partial specialization?

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175
  • Even this is not allowed : http://www.ideone.com/Vxx0R ... I wonder which section from the Standard disallows it. §14.5.4/9 applies here as well? – Nawaz May 12 '11 at 13:58
  • 2
    This is pretty much the same as, why no partial spec of functions when you can just wrap them in a struct? – Puppy May 12 '11 at 14:04
  • 1
    Why are you even using templates with this code? – J T May 12 '11 at 17:42

2 Answers2

15

I think a lot of it is historical. Non-type template parameters weren't originally allowed at all. When they were added, there were lots of limitations. As people tried different possibilities, and confirmed that they didn't cause problems, some of the limitations were removed.

Some of those original limitations remain for no particular reason beyond the fact that nobody bothered to work at changing them. Much like there, many of them can be worked around so removing them generally often wouldn't cause any particular difficulty. Mostly it comes down to a question of whether anybody cared enough about this particular case to write a paper about it.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035
-5

Partial specialisation requires that the non-type template argument be resolvable at compile time.

At this point

template<int N>
struct A<N, !(N % 5)> {
  /* ... */
};

N is a variable that can take more than one value and the compiler is unable to calculate N % 5 with certainty.

Your example instantiates a using

A<25> a;

but you could also have

A<25> a1;
A<15> a2;

How does the compiler choose a value for N in this scenario? It can't and so it has to disallow the code.

GManNickG
  • 459,504
  • 50
  • 465
  • 534
Tom Wilson
  • 660
  • 6
  • 9
  • 13
    I don't follow. It knows `N` because you're saying what it is. It's 25 or 15. – GManNickG May 12 '11 at 16:46
  • The use of partial specialisation tells the compiler to use a single specific instantiation for the second parameter. But here A<25> and A<15> are different types and so there would be more than a single instantiation. – Tom Wilson May 12 '11 at 18:04
  • 5
    I'm sorry, but I don't understand what you're saying. Yes, `A<25>` and `A<15>` are different types, what does that have to do with specialization? – GManNickG May 12 '11 at 18:25
  • that doesn't make sense to me either. – Johannes Schaub - litb May 12 '11 at 20:16
  • -1: Partial specialisation tells the compiler to use a single specific _definition_ when it encounters a set of matching template arguments. This definition will then generate different instantiations for each set of matching template arguments (in the same way that the generic template definition would). Only a complete specialisation would generate one instantiation. – Troubadour May 12 '11 at 21:24
  • Hmm - it seems that my analysis is incorrect - thanks @Troubadour – Tom Wilson Mar 17 '17 at 18:01