14

In 2003 - yes, 2003 - Vandervoorde and Josuttis wrote this in their book "C++ Templates" (p. 40):

Not being able to use floating-point literals (and simple constant floating-point expressions) as template arguments has historical reasons. Because there are no serious technical challenges, this may be supported in future versions of C++.

But this still doesn't work, even under C++11:

template<double D> //error
void foo() {}

Why was this not added?

Casey
  • 41,449
  • 7
  • 95
  • 125
roger.james
  • 1,478
  • 1
  • 11
  • 23
  • 11
    Given that floating-point equality is a slippery concept, I'm not sure how they could say "there are no serious technical challenges." I rather think this would be fraught with peril – Ernest Friedman-Hill Jul 18 '13 at 15:20
  • @ErnestFriedman-Hill: That seems like the basis of an answer to me. – John Dibling Jul 18 '13 at 15:21
  • We deal with equality issues in runtime code regularly, though. The same caveats would apply to their use in templates... I don't really see a good reason to keep them runtime-only. – Cory Nelson Jul 18 '13 at 15:22
  • @JohnDibling: not being involved in C++ compiler development, I would just be bloviating. I'd rather defer to the experts. – Ernest Friedman-Hill Jul 18 '13 at 15:24
  • @CoryNelson: But at runtime, you can compare differences to deltas, or use whatever strategy you want. The spec would have to mandate something. ULPs? A percentage? The part that scares me is that equality would almost certainly be a platform-dependent thing, and that could lead broad swaths of undefined behavior. – Ernest Friedman-Hill Jul 18 '13 at 15:26
  • 3
    @CoryNelson: The problem at compile time is that in some cases you don't want to compare for equality and that is fine, but in a template equality is *required* to determine whether the template specialization is the same or a new specialization needs to be generated. That is, at runtime equality is something that may or not be used, at compile time it **must** be used. – David Rodríguez - dribeas Jul 18 '13 at 15:38

3 Answers3

13

I had always assumed it had to do with matching implementations against each other. Like are these two instances the same or different:

template class foo<10./3.>
template class foo<1./3 * 10.>

They may not generate the same double-precision representation, so the compiler might think of them as different classes. Then you couldn't assign them to each other, etc.

JoshG79
  • 1,685
  • 11
  • 14
8

Lets look at the following code:

template<double D> int f(){
  static int i=0; 
  ++i; 
  return i;
}

...

#define D1=...
#define D2=...
cout << f<D1>()<<endl; // returns 1
cout << f<D1-D2+D2>()<<endl; // may return 1 or 2, depending on many things

See, D1-D2+D2 may be equal to D1 for some values but not equal for others.

More importantly - they may be equal or not depending on the rounding settings

And finally, they may be equal or not depending on compilers / architectures / many other things.

The point is, floating point operations are not well enough defined for template use (they are well defined, but there is a lot of possible variance depending on various options)

rabensky
  • 2,864
  • 13
  • 18
  • 1
    "dependent on settings" is no reason. `sizeof(Foo)` can also depend on settings, yet is unambiguously allowed. – MSalters Jul 18 '13 at 23:38
  • 1
    Yes, but settings for `sizeof` evaluate at compile time, and templates are also evaluated at compile time. Rounding settings, on the other hand, can change at runtime. This leads to a case where two floats are exactly equal (given runtime rounding settings), but their respective templates are different (as the calculation created them resulted in different values at compilation time). In my example, if you calculated `D1-D2+D2` at runtime you may get exactly `D1`, but the templates still evaluated to different functions. – rabensky Jul 19 '13 at 00:49
  • Your example seems strange. "May return 1 or 2". Yet D is not even used in the function. What am I missing? – roger.james Jul 19 '13 at 12:20
  • You are missing the "`static`" declaration of `i`. So `i` keeps its value between calls to the function. BUT - template functions with different template parameters are DIFFERENT functions, so each has its own `static i`. Hence if `D1==D1-D2+D2`, both calls to `f()` are to the same function (hence the same `i`, which has increased by `1`). But if they are not equal, it's two different functions each with its own `i` - so one call doesn't affect the other. – rabensky Jul 23 '13 at 18:29
6

When using floating point numbers, there is are lots of problem with rounding and equality. From the point of view of the normalizing committee, you need to ensure that two programs execute the same on several compilers. Therefore you need to specify very precisely what is the result of floating point operation. Probably they felt that the IEEE-754 norm is not precise enough...

So this is not a question of whether or not it is implementable but more of what precise behavior we want to have.

Note however that constexpr accept floating point values. This is usually enough for compile time computation.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
hivert
  • 10,579
  • 3
  • 31
  • 56