据我所知,noexcept 说明符中包含的表达式的值不会成为函数类型的一部分。*
N4618 §8.3.5/1 [dcl.fct] 状态(强调我的)
在声明 T D 中,D 的形式为
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt noexcept-specifier选择属性说明符序列选择
并且声明T D1 中包含的declarator-id 的类型是“derived-declarator-type-list T”, 的类型D 中的 declarator-id 是“derived-declarator-type-list noexceptopt (parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt 返回T”,其中可选的noexcept当且仅当异常规范 (15.4) 不抛出时才存在。可选的 attribute-specifier-seq 属于函数类型。
所以这意味着函数的类型要么包含noexcept,要么不包含;如果noexcept(expr) 中的表达式expr 计算结果为false,则函数的类型将完全排除关键字noexcept。
所以你不得不这样做:
template<typename T>
struct is_noexcept
{
static constexpr bool value = false;
};
template<>
struct is_noexcept<void() noexcept> {
static constexpr auto value = true;
};
但是,我认为这样的代码编译的事实具有误导性:
void (*fp)() noexcept(false);
因为下面函数的类型:
void foo() noexcept(false)
{
}
是void()。
以及以下函数的类型:
void bar() noexcept(true)
{
}
是void() noexcept
但是,我们可以这样做:
void (*fp)() noexcept(false) = &bar;
fp();
即使bar 被声明为noexcept,我们也可以将函数指针分配给它!所以这是误导; 我找不到它的标准参考,但似乎规则隐式允许此类转换以适应令人难以置信的向后兼容性。 §5/14.2 [expr] 讨论了这个 wrt 复合指针类型。
谢天谢地,这是非法的:
void (*fp)() noexcept(true) = &foo;
(请参阅 N4618 §4.13 [conv.fctptr] 中的示例以供参考)。
*将异常说明符集成到类型系统中是在N4320 中提出的(已被 C++17 标准采用)