MiB said:
The second template parameter is the culprit.
1. Only types and values of integral types are allowed as template
parameters - float is not an integral type,
so you cannot use it for a value template parameter.
Your wording is a little loose here. The three `kinds' or template
parameter are type, non-type and template template parameters. You are
referring to the OP's example in relation to non-type template
parameters (which you call a `value template parameter'). Your analysis
that a float cannot be used here is, however, broadly correct.
2. Also, you cannot use references as specifiers of value template
arguments:
This is not so, as stated. The key point here is that the non-type
template argument must be a run-time constant. The OP uses const T&
and, for this usage, the reference is perfectly acceptable (see below).
Note, however, that it the template argument itself must have external
linkage to satisfy the requirements of matching this parameter. It
must, also, be an lvalue.
the reference is in a way a hidden
pointer and receives a value at runtime. Template instantiation is
performed at compile time. Thus, while the
value of t is known by the compiler, its address in memory is not
yet determined and the template mechanism
must fail.
3. You did not give a name to the second parameter, only its type. How
do you plan to reference the value from
the instantiation in your class definition?
These need not always be an issue (see below).
The error messages you get are admittedly not very enlightening.
Summing it up:
template <class T, float t> class A {}; // illegal for reason #1
Agreed.
template <class T, int& i> class B {}; // illegal for reason #2
Illegal as given, but not *entirely* for the reason stated and, further,
not a good example with which to comment upon the users code, which uses
*const* T&. The effect of adding a reference here is *not* that
references are disallowed as such, but that a *non-const* reference does
not result in a compile-time constant. Consider:
template<class T, const T& t>
class B { };
extern const int i = 42;
B said:
template <class T, int> class C {}; // illegal for reason #3
Not *illegal* in any sense. Indeed, it is not even necessarily an
omission where the type may be used as a selector, for instance.
Consider:
template<class T, T>
class C { };
template<class T, T t>
void f(C<T, t>)
{
std::cout << "generic function called...\n";
}
template<>
void f<int, 42>(C<int, 42>)
{
std::cout << "specialization for C<int, 42> called...\n"
}
int main()
{
C<int, 41> c41;
C<int, 42> c42;
f(c41); f(c42);
}
/**
* Output:
* generic function called...
* specialization for C<int, 42> called...
*/
Note that the value of the second non-type template argument is
propogated to the instantion of the function f and is available there,
even though it is not directly named (nor available) within the
definition of C.
template <class T, T t> class D {};
D<float, 42.0f> d; // illegal for reason #1
delayed to instantiation.
D<int, 42> e; // this one should be OK.
Regards
Paul Bibbings