user5468942
user5468942

Reputation: 23

Non-type parameter templates. Why global and reference?

template<typename Body>
Body solve(Body a, Body b){
    Body zero(0);
    return zero;  
}

template<typename Body, Body& zero>
Body solve(Body a, Body b){
    return zero;
}

complex<double> zero(0);

int main() {
    complex<double> c1(1,2);
    complex<double> c2(3,4);    
    solve<complex<double>, zero_complex> (c1,c2);
    return 0;
}

Hi, I compiled above code and it is OK ( I omitted details here). Now, I noticed that zero must be a global variable and moreover templates must get zero by reference. Otherwise it causes a compilation error. I use c++11.

Please explain me why it must be:

  1. pass by reference
  2. global variable

Thanks in advance.

Upvotes: 0

Views: 76

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

Pointer and Reference parameters to templates are intended to allow you to write functions (or classes) that differ only in what global state they consume.

The location of the state they consume becomes part of their type (or name), and has to be determined at compile/link/load time.

Local variables (on the stack) have a different location -- not a constant one. The location cannot be determined at compile/link/load time.

The standard also limits what literals can be passed as a template parameter. One of the reasons behind this is that the link-time name of the symbol in question becomes a function of its non-type parameters: and naming each instance of Body in a way that is unique is hard.

To avoid that being a problem, they only allowed a limited set of values to be passed as non-type template parameters: reference, pointers, and integral values.

Presumably the problem with double was that the compile-time and run-time double precision and behavior could vary, which would make standardizing the behavior tricky. So, the standard just banned double and float.

A common technique is to replace constants with stateless functors. So you pass a "Body functor" instead of a Body constant.

The functor is stateless, and has a const operator() that returns a Body.

Upvotes: 2

SergeyA
SergeyA

Reputation: 62583

You can use references as template arguments, and this is what you are doing here. However, the variable you are taking reference to must have external linkage, and local variables do not have any linkage at all.

The other non-type template arguments you can use are pointers, and integral types, such as int. The same example of yours could be written in following way:

template<typename Body>
Body solve(Body a, Body b){
    Body zero(0);
    return zero;  
 }
template<typename Body, Body* zero>
   Body* solve(Body a, Body b){
   return zero;
}

int i = 0;
int main() {
  solve<int, &i>(10, 20);
}

Upvotes: 1

Related Questions