我很可能只是错过了MSVC 2022中可用的选项中的一些愚蠢的选项,这些选项的默认值发生了变化(如果是这样,请告诉我),但当我们在函数或类模板中间遇到错误时,我似乎无法获得编译时堆栈跟踪。
MSVC 2022中的基本示例:
template <class T>
void foo()
{
static_assert(false);
}
int main()
{
foo<int>();
}
在默认设置的MSVC 2022中,我得到的只是一个“static assert failed”类型的消息,它没有告诉我是谁调用了foo
。而在MSVC 2019中,我得到了一个完整的编译时堆栈跟踪,让我知道调用foo
失败了,精确到调用foo
的行。
我真的错过了2019年的额外信息。但我有一个偷偷的怀疑,有一些选项,在工具-〉选项,我不知道关于启用这种输出行为了。
图片:x1c 0d1x
还有人在从2019年升级到2022年后遇到这个问题和/或有修复程序吗?
MSVC 2019作为一个比较,我在模板中得到了错误消息,这些消息实际上可以帮助我找出它们发生的位置/方式!
而且,我只使用static_assert
来产生最小的和可重复的结果,我缺乏对函数或类模板中发生的每一种错误的堆栈跟踪。
针对研究中心的自动Q:
我试着浏览了所有我能找到的选项,并在谷歌沿着这个网站上搜索答案。公平地说,我现在是一个又老又笨的人,所以我可能忽略了一些显而易见的事情。我真的认为这是最明显的答案,因为MSVC 2022已经发布了很长时间,我想其他人会抱怨左和右的方式,我可以很容易地找到,如果这不是'我真的希望我忽略了一些东西,因为如果我们再也看不到类和函数模板中的编译时调用堆栈错误,那就太糟糕了(在许多情况下,这实际上忽略了关键信息,因为它可能不是模板/被调用方的错误,而是调用方调用被调用方的方式错误)。
堆栈跟踪?
我的错,如果我用错了术语。我得到了一个评论指出这一点。我正在考虑一些类似跟踪调用堆栈的东西(不是调用,而是在编译时以嵌套方式评估调用,因为我们解析、生成AST、生成IR、优化IR,等等)。如果我错误地使用了“编译时堆栈跟踪”,这可能是第二个问题。什么是正确的术语?英语不是我的第一语言,作为一个半借口,但我我可能真的很笨!
1条答案
按热度按时间dwbf0jvd1#
有机会从我的评论中测试我的理论。问题是试图符合标准。
您可能设置了
/permissive-
标志,以符合标准(使用C++20时为默认值)。这将为模板启用两个阶段名称查找。在Microsoft之前执行的非标准解析下:它只解析模板声明、类头和基类列表。模板主体被捕获为标记流。不解析函数主体、初始化器、默认参数或noexcept参数。类模板在一个试验类型上被伪示例化,以验证类模板中的声明是正确的。
...
当编译器解析一个函数模板时,它只解析函数签名,函数体永远不会被解析,而是被捕获为一个令牌流。
在这种非标准模式下,它会忽略
static_assert( false )
,直到它从main
示例化,在这种情况下,您将获得关于谁在示例化它的信息。在符合标准的模式下,它解析主体,看到
static_assert( false )
,然后在任何示例化完成之前立即失败。如果您想要旧的行为,可以通过指定
/permissive
来关闭标准一致性(尽管我不推荐这样做),也可以通过指定/Zc:twoPhase-
来禁用两阶段名称查找(同样,不推荐这样做查看更多信息:https://learn.microsoft.com/en-us/cpp/build/reference/zc-twophase?view=msvc-170
此外,此处为两相通断示例(并排):https://godbolt.org/z/MPEWGsYTx(godbolt在其输出中给出的细节比MS少,但确实显示了其示例化)
注意:如果问题出在调用方而不是被调用方,编译仍然会给出关于谁在示例化的信息。
有趣的是:当MS第一次这样做的时候,他们在这个过程中破坏了自己的代码,并且导致了大量的程序停止编译,因为他们在他们的单元测试框架中使用了
static_assert( false )
......我猜他们在推出它之前忘记了使用他们自己的单元测试:P