Visual Studio 2017中变量模板的除法返回零

3

这可能是与此问题相关的错误,如Visual Studio中使用Lambda表达式的模板变量错误?所述。正如评论中提到的,这似乎与优化器有关。


在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的错误?这里有没有解决方法?

1
有趣的是,如果在执行DEG_TO_RAD<float>之前尝试使用cout << PI<T> << endl,你会得到正确的结果。 - Algirdas Preidžius
1
auto test2 = DEG_TO_RAD<float>;得到了正确的结果,这应该是std::cout的问题。尝试设置更高的std::cout分辨率。 - lakeweb
1
看起来这是一个类型转换问题,因为 std::cout << (float)DEG_TO_RAD<float> 是可以工作的。 - lakeweb
@KillzoneKid 哦天哪!我改了那个以使链接的问题得以解决!这是怎么回事? - Jonathan Mee
@JonathanMee 我知道,对吧! - Killzone Kid
显示剩余14条评论
2个回答

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;
}

这是一张向微软提出的错误报告:https://developercommunity.visualstudio.com/content/problem/207741/template-needs-to-be-force-instantiated-vs2017-bug.html

0

我按原样测试了您的代码并得到了相同的结果。 但是,我还单独测试了PIONE_EIGHTY,它们在输出中给出了正确的结果。 所以我考虑了一下,由于我不知道Visual Studio为什么会这样做,这让我认为它可能是一个错误或者可能留给了编译器实现设计,但似乎它没有从两个预定义常量的除法中设置const T DEG_RAD

要在Visual Studio中解决此问题非常简单,很容易被忽视; 您只需用括号将RHS表达式包装起来即可。

template<typename T>
const T DEG_TO_RAD = (PI<T> / ONE_EIGHT<T>);

这样做将不会打印出正确的值,因为它会在将值分配给左侧const T变量声明为DEG_TO_RAD之前进行除法运算。

我不是100%确定,也不要引用我说的话,但从我的理解来看,这可能是运算符优先级顺序的问题。我认为在Visual Studio中,如果没有将RHS包装在括号中,它就无法正确执行除法操作,因此DEG_TO_RAD被设置为0。

编辑

这是我的完整代码:我正在使用标准库的大约80%来解决我在堆栈上回答问题时遇到的问题,因此我不会列出所有包含项,但我确实拥有大多数容器,I / O,数字,算法,内存,功能,计时器,cmath,GLM等。

在Win 7 - 64位Home Premium上使用Intel Quad Core Extreme的Visual Studio 2017 v15.4.4。

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种模式下尝试了这个:Debug/Release x86和x64,结果都一样。 这可能因为你的机器平台不同而有所不同。


嗯;我正在使用VS 2017,它在Win7 64位家庭高级版上运行良好。 - Francis Cugler
你是在32位还是64位模式下编译的?是调试版还是发布版?有任何特殊优化吗? - Francis Cugler
哪个版本?我使用的是15.5.7。 - Killzone Kid
嗯,我有旧版本的15.4.4。 - Francis Cugler
1
尝试在 cout 之前添加 PI<float>;,这对我有效。 - Killzone Kid
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接