问题
This is probably a visual-studio-2017 bug related to this question: Templated Variables Bug With Lambdas in Visual Studio? And as mentioned in the comments there seems to be optimizer related.
Division in the definition of a variable template seems to have a bug in Visual Studio 2017. So this code for example:
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;
}
On gcc 6.3 this outputs:
0.0174533
On Visual Studio 2017 this outputs:
0.0
I'm assuming this is another Visual Studio bug? Is there a workaround here?
回答1:
Posting a workaround here at the request of @JonathanMee as it also works for the similar problem reported by him earlier. Seems to be connected with some sort of bug in latest VS2017 that prevents template from activating automatically and needs a force activation:
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;
}
Here is a bug ticket filed with Microsoft: https://developercommunity.visualstudio.com/content/problem/207741/template-needs-to-be-force-instantiated-vs2017-bug.html
回答2:
I tested your code as is and got the same results. However I also tested PI
& ONE_EIGHTY
individually and they were giving me the correct results in the output. So I had thought about it, and for some reason as I don't know why Visual Studio is doing this which leads me to think that it could be a bug or that it could be left to the compiler-implementation-design
but it appears that it is not setting the const T DEG_RAD
from the division of the two predefined constants.
To fix this problem in visual studio it is quite simple and easily over looked; all you have to do is wrap the RHS expression with parenthesis.
template<typename T>
const T DEG_TO_RAD = (PI<T> / ONE_EIGHT<T>);
And this will not print out the correct values as it will do the division before assigning the value to the LHS const T
variable declared as DEG_TO_RAD
.
I'm not 100% certain and don't quote me on this, but from my own understanding I think this could be an issue of operator precedence order. I think in visual studio without wrapping the RHS in parenthesis it is not performing the operation of division properly thus DEG_TO_RAD
is being set to 0.
EDIT
Here is my full code: I am using about 80% of the standard library for my particular solution for when I try to work out problems to answer here on stack so I will not list all of the includes but I do have most all containers, I/O, numeric, algorithms, memory, functional, chrono, cmath, GLM etc.
Using Visual Studio 2017 v15.4.4 on Win 7 - 64bit Home Premium on a 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;
}
Output:
3.14159
180
0
Then when I do this:
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;
}
Output:
3.14159
180
0.0174533
I tried this in all 4 modes: Debug/Release x86 & x64 and I get the same results. This may be different on your machine - platform.
来源:https://stackoverflow.com/questions/49118587/division-in-variable-template-returns-zero-in-visual-studio-2017