user1095108
user1095108

Reputation: 14603

float conversions in templates

Take this function template:

template <typename T>
T divby2(T a)
{
  return .5 * a;
}

Does there exist a way to specify (.5), a double constant, so that it won't be converted at run time into T when T != double (say, when T is float)?

Some ideas for alternative specifications of the .5 constant:

template <typename T>
T divby2(T a)
{
  return T(.5) * a;
}

template <typename T>
T divby2(T a)
{
  return (T(1) / T(2)) * a;
}

Upvotes: 0

Views: 210

Answers (1)

Arne Mertz
Arne Mertz

Reputation: 24626

There are no decisions made about conversions at runtime. The decision to convert a value to another type or not is made at compiletime.

  • .5 will be a double, no matter what.
  • a will be whatever template specialization you have, i.e. of type T
  • The result type of the multiplication (let's call it X) will be whatever operator*(double, T) gives. A double for all the builtin numbers, except for long double, where it gives a long double
  • Since you are returning a T, the X returned by the multiplication will be converted into a T
  • And T(0.5) will be always a T.

If any of those conversions or the operator* are not defined, you get a compile time error. Types have nothing to do with runtime (unless you have virtual functions and the like).

To your comment: T(.5) is an expression of type T. The conversion of the values will conceptually take place at runtime. However, the compiler is allowed to optimize that away, e.g. if T is int, the compiler would instantiate the T(.5) with int(.5) and could immediately optimize that to 0.

From your questions I assume that you might not be aware of the nature of templates. Templates are evaluated and instantiated at compiletime, unlike generic functions in some other languages. Template instantiation means, that the compiler generates independent functions for each type you use the template with. So e.g. if you use that function with T=double, T=int and T=long double in different places it would be as if you had written three functions:

double divby2(double a)
{
  return .5 * a;
}

int divby2(int a)
{
  return .5 * a;
}

long double divby2(long double a)
{
  return .5 * a;
}

In the first function, no conversions will take place at all, because everything is double. In the second function, the compiler knows that double multiplied by an int gives a double, but that double is converted back to int. You might get warnings about that. In the third function, the multiplication of a double and a long double gives a long double. Since the return type is a long double as well, everything is fine and you won't get warnings.

Upvotes: 6

Related Questions