Suppose your nested template declaration were just a little more complicated:
template <typename T, int I>
struct A {
template <typename S, I>
void f (const A<S, I> &s);
template <typename S, int J>
friend struct A;
// Question 1: why isn't the syntax 'friend struct A<S, J>' ?
// The semantic would stay, since we would like A<S, J> (for ANY S, J combination) to be friend of every A<T, I>..
private:
void g () const {}
};
template <typename T, int I>
template <typename S> // Question 2: Why can't the syntax be 'template <typename T, int I, typename S>' ?
void A<T>::f (const A<S> &s) {
s.g();
}
int main () {
A<bool, 5> abool;
A<char, 7> achar;
abool.f(achar);
}
Suddenly your suggestion doesn't seem so reasonable or obvious anymore. Which set of arguments goes first? Suppose you were using C++0x and had a variable argument list?
As for the friend declaration, by having the syntax you propose (friend struct <S, J>
), you suddenly make the compiler have to deduce that S
and J
are meant as template arguments and should not be grabbed from some random scope. Suppose someone introduced a type S
at the same scoping level as struct A
? Which S
would the declaration friend struct A<S,J>
refer to? How would the compiler know? Is it reasonable to have the introduction of a name in an outer scope to radically change the meaning of a declaration in a nested scope?
And if you meant that the declaration should read, in total: template <typename S, int J> friend struct A<S, J>
, then why should a friend forward template declaration look any different from a standard template declaration? It's redundant to include the names of the template variables after the name of the template when you already mention them in the template <typename S, int J>
part.
I also think your suggested syntax would make figuring out what a template specialization is doing a lot harder because you'd have to look at more parts of the code and correlate things.
As an example, a template specialization of my version of A
would look like this:
template <typename T>
struct A<T, 5> {
};
And as you can see, this is strangely close to your suggested friend forward declaration syntax, and it might be hard to tell whether or not you're intending to specify a specialized version or not. It would require matching up template arguments with template parameters whereas in the way it's currently done, if you have no template parameters you aren't talking about a specialization.