Почему double не разрешен в качестве параметра шаблона непигового типа?

В 2003 году - да, 2003 - Vandervoorde и Josuttis написали это в своей книге "С++ Templates" (стр. 40):

Невозможно использовать литералы с плавающей запятой (и простые константные выражения с плавающей запятой), поскольку аргументы шаблона имеют исторические причины. Поскольку нет серьезных технических проблем, это может быть поддержано в будущих версиях С++.

Но это все еще не работает, даже в С++ 11:

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

Почему это не добавлено?

Ответ 1

Я всегда считал, что это связано с сопоставлением реализаций друг с другом. Например, эти два экземпляра одинаковы или различны:

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

Они не могут генерировать одно и то же представление с двойной точностью, поэтому компилятор может думать о них как о разных классах. Тогда вы не можете назначить их друг другу и т.д.

Ответ 2

Давайте рассмотрим следующий код:

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

См., D1-D2+D2 может быть равно D1 для некоторых значений, но не равно для других.

Более важно - они могут быть равны или не зависят от настроек округления

И, наконец, они могут быть равны или не зависят от компиляторов/архитектур/много других вещей.

Дело в том, что операции с плавающей запятой недостаточно хорошо определены для использования шаблонов (они хорошо определены, но существует много возможной дисперсии в зависимости от различных параметров)

Ответ 3

При использовании чисел с плавающей запятой существует множество проблем с округлением и равенством. С точки зрения нормативного комитета вам необходимо убедиться, что две программы выполняют одно и то же на нескольких компиляторах. Поэтому вам нужно точно указать, что является результатом операции с плавающей запятой. Вероятно, они чувствовали, что норма IEEE-754 недостаточно точна...

Итак, это не вопрос того, реализуется ли это, но больше того, какое точное поведение мы хотим иметь.

Обратите внимание, что constexpr принимает значения с плавающей запятой. Обычно этого достаточно для вычисления времени компиляции.