2013-07-18 3 views
11

В 2003 году - да, - Vandervoorde и Josuttis писал в своей книге "C++ Templates" (стр 40).:Почему double нельзя использовать в качестве параметра шаблона непигового типа?

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

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

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

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

+11

Учитывая, что с плавающей точкой равенство скользкое Я не уверен, как они могли бы сказать «нет серьезных технических проблем». Я скорее думаю, что это было бы чревато опасностью. –

+0

@ ErnestFriedman-Hill: Это похоже на основу ответа на меня. –

+0

Мы регулярно занимаемся вопросами равенства во время выполнения кода. Те же предостережения применимы к их использованию в шаблонах ... Я действительно не вижу веских оснований держать их в режиме исполнения только. –

ответ

10

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

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

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

5

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

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

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

7

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

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 для некоторых значений, но не равны для других.

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

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

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

+0

«в зависимости от настроек» не является основанием. 'sizeof (Foo)' также может зависеть от настроек, но недвусмысленно разрешено. – MSalters

+1

Да, но настройки для 'sizeof' оцениваются во время компиляции, а шаблоны также оцениваются во время компиляции. С другой стороны, параметры округления могут меняться во время выполнения. Это приводит к случаю, когда два поплавка в точности равны (заданы параметры округления во время выполнения), но их соответствующие шаблоны различны (поскольку созданный ими расчет привел к разным значениям во время компиляции). В моем примере, если вы рассчитали 'D1-D2 + D2' во время выполнения, вы можете получить именно« D1 », но шаблоны все еще оцениваются для разных функций. – rabensky

+0

Ваш пример кажется странным. «Может вернуться 1 или 2». Тем не менее D даже не используется в функции. Что мне не хватает? –

Смежные вопросы