tags:

views:

160

answers:

4

The following code yields an error error: ‘struct Foo’ is not a valid type for a template constant parameter:

template <struct Foo>
struct Bar {

};

Why is that so?

template <class Foo>
struct Bar {

};

works perfectly fine and even accepts an struct as argument.

+3  A: 

You can instantiate a template using a struct; however, the syntax for declaring a template type only allows the keywords "class" or "typename" to appear where you are attempting to use the keyword "struct".

I should add that you can also use a specific type (e.g. int), if you want to instantiate your template based on a compile-time constant or based on an object with external linkage... but that's somewhat of an aside.

Michael Aaron Safyan
+2  A: 

Because the keyword for template parameters is class or typename. This doesn't restrict the Foo parameter to be a class - it can be of any type.

Kasprzol
+7  A: 

This is just an artifact of the syntax rules - the syntax just lets you use the class or typename keywords to indicate a type template parameter. Otherwise the parameter has to be a 'non-type' template parameter (basically an integral, pointer or reference type).

I suppose Stroustrup (and whoever else he might have taken input from) decided that there was no need to include struct as a a keyword to indicate a type template parameter since there was no need for backwards compatibility with C.

In fact, my recollection (I'll have to do some book readin' when I get back home) is that when typename was added to indicate a template type parameter, Stroustrup would have liked to take away using the class keyword for that purpose (since it was confusing), but there was too much code that relied on it.


Edit:

Turns out the story is more like (from a blog entry by Stan Lippman):

The reason for the two keywords is historical. In the original template specification, Stroustrup reused the existing class keyword to specify a type parameter rather than introduce a new keyword that might of course break existing programs. It wasn't that a new keyword wasn't considered -- just that it wasn't considered necessary given its potential disruption. And up until the ISO-C++ standard, this was the only way to declare a type parameter.

Reuses of existing keywords seems to always sow confusion. What we found is that beginners were [wondering] whether the use of the class constrained or limited the type arguments a user could specify to be class types rather than, say, a built-in or pointer type. So, there was some feeling that not having introduced a new keyword was a mistake.

During standardization, certain constructs were discovered within a template definition that resolved to expressions although they were meant to indicate declarations

...

The committee decided that a new keyword was just the ticket to get the compiler off its unfortunate obsession with expressions. The new keyword was the self-describing typename.

...

Since the keyword was on the payroll, heck, why not fix the confusion caused by the original decision to reuse the class keyword. Of course, given the extensive body of existing code and books and articles and talks and postings using the class keyword, they chose to also retain support for that use of the keyword as well. So that's why you have both.

Michael Burr
I've been using `template <typename ...>` as long as I can remember, I believe the `class` part confuses people thinking it's the actual `class` and want to stick `struct` in there for some strange reason ...
stefanB
At least in his C++0x FAQ (http://www2.research.att.com/~bs/C++0xFAQ.html), Stroustrup appears to be using `typename` and `class` in a completely arbitrary way. There's probably no way to avoid the "confusion", because sooner or later you'll run into code that uses `class` (which is just less typing in generally verbose template code, IMO) and you'll have to know that there's no difference anyway.
UncleBens
+2  A: 

The short answer is: template <class Foo> even accepts a union or a double - still, neither is allowed instead of class. However, typename is. That's just the way the syntax was defined.

A somewhat longer answer: When templates for C++ where "invented", there was a keyword needed at that place saying that the next identifier would be a type name. It was decided to re-use the existing class keyword. That was a bit confusing, but there's a general reluctance to introducing more keywords, because they always break some existing code which used this as an identifier when it wasn't a keyword.

Later, typename became a keyword for other reasons, and since it is a much better fit, it can now be used in that place: template <typename Foo>. However, with billions of lines of code out there using class in that place, it must remain valid for that purpose. So now both are allowed.

As is common in C++, this created several camps as to what keyword to use in that place. Some stick with class, because they've been using it for more than a decade. Others prefer typename, because it's a much better fit. Some use class when Foo is expected to be of a class type (members are accessed) and typename when built-ins can be used, too.

sbi