Разделение в шаблоне переменных возвращает ноль в Visual Studio 2017
Вероятно, это ошибка /questions/tagged/visual-studio-2017, связанная с этим вопросом: Ошибка шаблонных переменных в Lambdas в Visual Studio? И, как упоминалось в комментариях, похоже, что это связано с оптимизатором.
Деление в определении шаблона переменной, по- видимому, имеет ошибку в Visual Studio 2017. Так, например, этот код:
template <typename T>
const T PI = std::acos(static_cast<T>(-1));
template <typename T>
const T ONE_EIGHTY = 180;
template <typename T>
const T DEG_TO_RAD = PI<T> / ONE_EIGHTY<T>;
int main() {
cout << DEG_TO_RAD<float> << endl;
}
На gcc 6.3 это выводит:
0.0174533
На Visual Studio 2017 это выводит:
0.0
Я предполагаю, что это еще одна ошибка Visual Studio? Есть ли обходной путь здесь?
2 ответа
Публикация обходного пути здесь по запросу @JonathanMee, так как он также работает для аналогичной проблемы, о которой он сообщал ранее. Кажется, что это связано с некоторой ошибкой в последней версии VS2017, которая препятствует автоматической активации шаблона и требует принудительной активации:
template <typename T>
const T PI = std::acos(static_cast<T>(-1));
template <typename T>
const T ONE_EIGHTY = 180;
template <typename T>
const T DEG_TO_RAD = PI<T> / ONE_EIGHTY<T>;
int main()
{
PI<float>; // <---- workaround
std::cout << DEG_TO_RAD<float> << std::endl;
}
Вот заявка на ошибку, поданная в Microsoft: https://developercommunity.visualstudio.com/content/problem/207741/template-needs-to-be-force-instantiated-vs2017-bug.html
Я проверил ваш код как есть и получил те же результаты. Однако я также проверил PI
& ONE_EIGHTY
индивидуально, и они давали мне правильные результаты на выходе. Так что я подумал об этом, и по какой-то причине, так как я не знаю, почему Visual Studio делает это, что заставляет меня думать, что это может быть ошибкой или что ее можно оставить compiler-implementation-design
но похоже, что он не устанавливает const T DEG_RAD
от деления двух предопределенных констант.
Устранить эту проблему в visual studio довольно просто и легко просматривается; все, что вам нужно сделать, это обернуть выражение RHS в круглые скобки.
template<typename T>
const T DEG_TO_RAD = (PI<T> / ONE_EIGHT<T>);
И это не будет выводить правильные значения, как это будет деление до присвоения значения LHS const T
переменная объявлена как DEG_TO_RAD
,
Я не уверен на 100% и не цитирую меня об этом, но, исходя из собственного понимания, я думаю, что это может быть проблемой порядка приоритета операторов. Я думаю, что в Visual Studio, не заключая RHS в круглые скобки, он не выполняет операцию деления должным образом. DEG_TO_RAD
устанавливается на 0.
РЕДАКТИРОВАТЬ
Вот мой полный код: я использую около 80% стандартной библиотеки для своего конкретного решения, когда я пытаюсь решить проблемы, чтобы ответить здесь в стеке, поэтому я не буду перечислять все включения, но у меня есть почти все контейнеры, I/O, числовые, алгоритмы, память, функционал, хроно, cmath, GLM и т. Д.
Использование Visual Studio 2017 v15.4.4 на Win 7 - 64bit Home Premium на Intel Quad Core Extreme.
template <typename T>
const T PI = std::acos( static_cast<T>(-1) );
template <typename T>
const T ONE_EIGHTY = 180;
template <typename T>
const T DEG_TO_RAD = PI<T> / ONE_EIGHTY<T>;
int main() {
std::cout << PI<float> << std::endl;
std::cout << ONE_EIGHTY<float> std::endl;
std::cout << DEG_TO_RAD<float> std::endl;
_getch(); // include <conio.h> // just to stop the debugger from auto close
return 0;
}
Выход:
3.14159
180
0
Затем, когда я делаю это:
template <typename T>
const T PI = std::acos( static_cast<T>(-1) );
template <typename T>
const T ONE_EIGHTY = 180;
template <typename T>
const T DEG_TO_RAD = (PI<T> / ONE_EIGHTY<T>);
int main() {
std::cout << PI<float> << std::endl;
std::cout << ONE_EIGHTY<float> std::endl;
std::cout << DEG_TO_RAD<float> std::endl;
_getch(); // include <conio.h> // just to stop the debugger from auto close
return 0;
}
Выход:
3.14159
180
0.0174533
Я попробовал это во всех 4 режимах: отладка / выпуск x86 и x64, и я получаю одинаковые результаты. Это может отличаться на вашей машине - платформе.