为什么这段使用__LINE__的代码在MSVC Release模式下可以编译,但在Debug模式下却不能?

19

考虑这个程序:

#include <iostream>

template<bool Debug = false, int Line = __LINE__>
constexpr int adds(const int& a, const int& b) { 
    if (Debug)
        std::cout << __FUNCTION__ << " called on line " << Line << '\n';
    return (a + b);
}

int main() {
    std::cout << adds(3, 7) << '\n';
    std::cout << adds<true, __LINE__> (5, 9) << '\n';
    return 0;
}

当我尝试在Debug模式下编译和构建此代码时,Visual Studio 2017会生成以下编译器错误:

1>------ Build started: Project: Simulator, Configuration: Debug x64 ------
1>main2.cpp
1>c:\***\main2.cpp(12): error C2672: 'adds': no matching overloaded function found
1>c:\***\main2.cpp(12): error C2975: 'Line': invalid template argument for 'adds', expected compile-time constant expression
1>c:\***\main2.cpp(3): note: see declaration of 'Line'
1>Done building project "Simulator.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

但是,当我尝试在Release模式下执行此操作时:它编译、构建、运行并生成适当的输出:

10
adds called on line 12
14

这是一个潜在的Visual Studio 2017错误吗?如果不是,为什么它在一种模式下工作而在另一种模式下不工作?

您可以在此处查看编译结果:Compiler Explorer


以下是调试和发布模式的命令行标志的副本:

调试

/JMC /permissive- /GS /W3 /Zc:wchar_t /Qspectre /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++latest /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Simulator.pch" /diagnostics:classic 

发布

/permissive- /GS /GL /W3 /Gy /Zc:wchar_t /Qspectre /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc141.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /std:c++latest /FC /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\Simulator.pch" /diagnostics:classic 

你能展示一下调试和发布配置吗?(即它们使用哪些编译器标志) - Guy Incognito
@GuyIncognito 除了将语言标志设置为“ISO C++ Latest Draft Standard (/std:c++latest)”以适用于所有配置和平台之外,一切基本上都是标准的……其他都是Visual Studio默认设置。 - Francis Cugler
1
酷,VS 的默认设置是什么? - Guy Incognito
这可能是C++编译器的问题,而不是Visual Studio的问题。 - Alejandro
1个回答

22

似乎有人报告了这个问题:__LINE__ 无法用作 constexpr 函数的参数

我们在 C++ 团队中已经了解到此问题存在的已知 bug。
[...]
我们已经确定,这不是一个 bug。请参考 Jonathan 的评论。

而 Jonathan 说:

这是编译器支持 Edit-and-Continue 的一种副作用(基本上我们不希望将 __LINE__ 的值更改视为“冒失编辑”,从而抑制 Edit-and-Continue):如果你使用 /Zi 而不是 /ZI 编译代码,则代码应该可以编译(但可执行文件将不支持 Edit-and-Continue)。
[...]
该错误被认为是一种特性...

来自 MSVC 文档

/ZI选项类似于/Zi,但它会生成支持编辑和继续 (Edit and Continue) 功能的PDB文件。 [...] /ZI选项还与使用__LINE__预定义宏不兼容;使用/ZI编译的代码无法将__LINE__用作非类型模板参数,尽管__LINE__可以在宏扩展中使用。

然而,在发布模式下尝试时:它编译、构建、运行并生成了适当的输出:

我想原因是/ZI/Zi标志的区别。您的发布模式标志具有/Zi,所以编译顺利。


1
很高兴知道!这是你偶然遇到的那些罕见事情之一...但是知道这个还是很好的!尽管如此,一旦C++20得到全面支持并完全成为主流,这将不再是太大的麻烦! - Francis Cugler
1
如果你想尝试的话,还有clang(你可以在VS中使用它)。我听说它很不错 ;) - Waqar
1
@Waqar 嗯,我也在使用Python和JavaScript做其他事情...我只是喜欢C++在后端库代码库中的强大、控制和效率...而且是的,在调试模式下将“/ZI”更改为“/Zi”可以解决问题...说实话,我甚至不确定自己是否曾经利用过“编辑并继续”功能...我已经从头开始构建了工作的3D图形-游戏引擎,使用OpenGL和DirectX,并开始学习Vulkan。我的当前爱好项目是尝试从头开始构建电路模拟器!我已经完成了硬件仿真(NES)... - Francis Cugler
1
@FrancisCugler 我提到了 Clang,它是免费可用的。是的,Intel编译器ICC不是免费的,但它们为FOSS项目提供免费许可证(对此我也不确定)。据说它可以为Intel架构生成更快的代码(我还没有尝试过,所以不能确定)。 - Waqar
1
根据这种哲学,我认为VC遵循标准比clang和gcc要好得多,因为后者以无意义的方式处理源文本,而其行为是由标准定义的,但不符合clang和gcc使用的抽象模型。 - supercat
显示剩余6条评论

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