提问者:小点点

Clang constexpr 编译错误在 lambda、gcc 和 msvc ok。叮当虫?


我在使用此代码的 clang 中遇到了编译错误。我认为它没有任何问题,它可以在 msvc 和 gcc 中工作。我错过了什么还是叮当声?

#include <iostream>
#include <string>
#include <type_traits>

constexpr bool do_tests()
{
    // prints error message at runtime if test is false
    auto verify = [](bool test, std::string message = "error") {
        if (!std::is_constant_evaluated() && !test)
            std::cout << message << '\n';
        return test;
    };
    return verify(1 == 1, "test");
};


int main()
{
    constexpr bool b = do_tests();
    std::cout << b << '\n';
}

编译器资源管理器

来自叮当的莫名其妙的错误消息:

basic_string.h:356:10:注意:常量表达式中不允许将没有活动成员的联合的成员“_M_local_buf”分配给成员


共1个答案

匿名用户

代码没有问题,如果你使用libc(-stdlib=libc),Clang也可以正确编译它。编译器资源管理器默认使用 libstdc for Clang (-stdlib=libstdc)。两者之间似乎只是存在兼容性问题。我的猜测是,libstdc 正在以一种技术上不允许在常量表达式中实现 constexpr 字符串的方式,但 GCC 在这方面往往不如 Clang 那么严格,因此 Clang 在实现时失败,而 GCC 没有问题。

更准确地说,在libstdc中,std::string的实现包含一个匿名联合,其中一个成员是一个名为_M_local_buf_CharT数组。那么,如果计算发生在常量表达式计算中,libstdc 将执行以下操作(从 https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/bits/basic_string.h#L355 开始)

for (_CharT& __c : _M_local_buf)
    __c = _CharT();

为了将工会成员_M_local_buf设置为活动并将其归零。

问题在于,在此循环之前,没有将联合的任何成员设置为活动,并且通过引用而不是直接通过名称或通过成员访问表达式设置成员(子对象)在技术上没有在标准中指定将成员设置为活动。因此,从技术上讲,它具有未定义的行为,这就是为什么Clang(正确)不想接受它作为常量表达式的原因。如果事先将成员设置为活动状态,例如使用额外的行 _M_local_buf[0] = _CharT(); 那就没问题了。

当然,直接设置 _M_local_buf[0] 似乎有点愚蠢,但通过引用__c设置它就不行了,这可能就是为什么 GCC 仍然接受它作为常量表达式的原因,我想可能存在 CWG 问题。

这里有一个与非常相似的问题相关的libstdc错误报告,但这已经应该修复一段时间了。

似乎提交 https://github.com/gcc-mirror/gcc/commit/98a0d72a610a87e8e383d366e50253ddcc9a51dd 已经(重新)引入了您在此处看到的特定问题。在提交之前,成员已正确设置为活动状态。打开一个关于这个问题的问题可能是值得的,尽管如上所述,Clang在这里非常迂腐,并且正如链接的错误报告也说的那样,可能应该更改标准以允许这样做。