template with const as parameter

C

charlie

Hi,

I would like to ask a question here:

const float t = 0;
template < class T, const T& >
class A {
public:
A();
};
typedef A<float, t> AA;

why above doesn't work and gives following errors?

tCR.cpp:14: error: wrong number of template arguments (1, should be 2)
tCR.cpp:10: error: provided for 'template<class T, const T&
<anonymous> > class A'
tCR.cpp:14: error: invalid type in declaration before ';' token

Thanks!

Charlie
 
P

ptyxs

Hi,

I would like to ask a question here:

const float t = 0;
template < class T, const T& >
class A {
public:
  A();};

typedef A<float, t> AA;

why above doesn't work and gives following errors?

tCR.cpp:14: error: wrong number of template arguments (1, should be 2)
tCR.cpp:10: error: provided for 'template<class T, const T&
<anonymous> > class A'
tCR.cpp:14: error: invalid type in declaration before ';' token

Thanks!

Charlie

In
A<float, t> AA
t should be a type and it is a variable, not a type (whereas float,
is, obviously).
 
M

MiB

const float t = 0;
template < class T, const T& >
class A {
public:
  A();};

typedef A<float, t> AA;

why above doesn't work and gives following errors?

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.
2. Also, you cannot use references as specifiers of value template
arguments: 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?

The error messages you get are admittedly not very enlightening.

Summing it up:

template <class T, float t> class A {}; // illegal for reason #1
template <class T, int& i> class B {}; // illegal for reason #2
template <class T, int> class C {}; // illegal for reason #3

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.

best,

MiB.
 
P

Paul Bibbings

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
 
V

Victor Bazarov

In
A<float, t> AA
t should be a type and it is a variable, not a type (whereas float,
is, obviously).

Read up on non-type template arguments, please.

V
 
J

James Kanze

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,

This is false. A non-type template parameter may be 1) an
integral or enumeration type, 2) a pointer to an object or
a function, 3) a reference to an object or a function, or 4)
a pointer to member. His parameter corresponds to 3.
so you cannot use it for a value template parameter.
2. Also, you cannot use references as specifiers of value template
arguments: 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.

§14.1/4 says otherwise, and explicitly lists references as legal
parameters.
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?

That shouldn't stop the code from compiling.
The error messages you get are admittedly not very enlightening.

No. It does look like the compiler got confused.

In fact, the problem with his code is a frequent one: the
arguments to a template must have external linkage, and const
variables at namespace scope have internal linkage by default.
Just change the first line to:

extern float const t = 0;

and his code works. The problem has nothing to do with
float---I've had similar problems (with a similar fix) for
char const*.
 
J

James Kanze

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.

It's not correct at all, since the original poster doesn't use
a float; he uses a reference to a float.
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 external linkage is, in fact, the only relevant issue here.

And of course, since nothing that isn't an lvalue has linkage,
the initializing expression must be an lvalue, constant
expression.

The standard requires it to work, and it does work with the
compilers I've seen.
These need not always be an issue (see below).

But irrelevant with regards to the original code.
Illegal as given,

Perfectly legal.
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:

A reference is always constant. The only issue here is that the
*argument* must be a non-const lvalue with external linkage.
Declare
int i;
and you can use i as the second argument of the template
(provided that the definition is at namespace scope, of course).
template<class T, const T& t>
class B { };
extern const int i = 42;
B<int, i> b; // OK
Not *illegal* in any sense. Indeed, it is not even necessarily an
omission where the type may be used as a selector, for instance.

It's actually a fairly common technique.
 
P

Paul Bibbings

James Kanze said:
Perfectly legal.

You are indeed correct. I had initially believed this to be correct,
too, but had thought that I had tested it and found it to be not so
(which surprised me). I must have either allowed an error into the test
or, more likely, simply `tested' something else altogether! :)

Regards

Paul Bibbings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,157
Latest member
MercedesE4
Top