Разделение в шаблоне переменных возвращает ноль в 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, и я получаю одинаковые результаты. Это может отличаться на вашей машине - платформе.

Другие вопросы по тегам