当我偶然发现一个奇怪的行为时,我试图static_assert
一些类型特征以确保自定义类型具有预期的noexcept
保证。上面的简化代码段说明了这个问题:
struct DefaultOnly
{
constexpr DefaultOnly() noexcept(false) {};
};
static_assert(std::is_nothrow_default_constructible_v<DefaultOnly>);
对于这个简单的类型,GCC 8 通过了 static_assert
而 Clang 7 没有通过。我不知道哪个编译器是正确的。这是其中一个编译器中的错误,还是nothrow default constructible 的标准定义足够灵活,以至于两个编译器都根据对标准的解释产生有效但不同的结果?
最佳答案
这个问题与具有 noexcept
规范的构造函数没有直接关系,而是在 noexcept
起作用时编译器如何处理常量表达式。
如果您将构造函数声明为 no constexpr
,那么两个编译器都会按预期工作:
struct DefaultOnly
{
DefaultOnly() noexcept(false) {};
};
static_assert(std::is_nothrow_default_constructible_v<DefaultOnly>);
回到 C++11,常量表达式 对 noexcept
规范不敏感,但它经历了直到 C++17 的更改。到目前为止,constexpr
函数受 noexcept
规范影响。
Clang 按预期工作。
以下代码将显示与您的行为相同的行为:
constexpr int foo() noexcept(false) { return 0;}
static_assert(noexcept(foo()));
作为引用,这是 GCC-87603 的摘录报告:
CWG 1129 (which ended up in C++11) added a special case to noexcept for constant expressions, so that:
constexpr void f() {} static_assert(noexcept(f()));
CWG 1351 (which ended up in C++14) changed the wording significantly, but the special case remained, in a different form.
P0003R5 (which ended up in C++17) changed the wording again, but the special case was removed (by accident), so now:
constexpr void f() {} static_assert(!noexcept(f()));
According to Richard Smith in LLVM 15481, CWG discussed this but decided to keep the behavior as-is. Currently, clang does the right thing for C++17 (and fails for C++14 and C++11, on purpose). g++, however, implemented the special case for C++11 already, but not the change for C++17. Currently, icc and msvc seem to behave like g++.
关于c++ - is_nothrow_default_constructible 带有 noexcept(false) 默认构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53900608/