对于下面的程序,Clang 5(主干)报告IsNoexcept
不能被推导,而GCC 7.1段错误。 标准(草案)对此有何评价?这是编译器QOI问题吗?
static_assert(__cpp_noexcept_function_type, "requires c++1z");
template<typename T>
struct is_noexcept;
template<bool IsNoexcept>
struct is_noexcept<void() noexcept(IsNoexcept)> {
static constexpr auto value = IsNoexcept;
};
static_assert(is_noexcept<void() noexcept>::value);
static_assert(!is_noexcept<void()>::value);
int main() {}
与提案P0012有关。
答案 0 :(得分:4)
noexcept
推断以简化std::is_function
的实施。看起来扩展只是经过了非常轻微的测试。这不是一致的扩展,因为它改变了明确定义的代码的含义,例如,使用以下代码段的g(f)
的值:
void f() noexcept;
template<bool E = false, class R>
constexpr bool g(R (*)() noexcept(E)){
return E;
}
答案 1 :(得分:1)
据我所知,noexcept
说明符中包含的表达式的值不会成为函数类型的一部分。*
N4618§8.3.5/ 1 [dcl.fct]陈述(强调我的)
在声明
T D
中D
的形式为<D1
( parameter-declaration-clause ) cv-qualifier-seq opt ref-qualifier opt noexcept-specifier < sub> opt attribute-specifier-seq opt
并且声明T D1
中包含的 declarator-id 的类型是“ derived-declarator-type-listT
”,类型D
中的 declarator-id 是“ derived-declarator-type-listnoexcept
opt 函数(< em> parameter-declaration-clause ) cv-qualifier-seq opt ref-qualifier opt 返回T
“ ,当且仅当异常规范(15.4)非抛出时,存在可选的noexcept
。可选的 attribute-specifier-seq 属于函数类型。
所以这意味着函数的类型包括noexcept
或不包括noexcept(expr)
;如果false
中的表达式 expr 评估为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
被声明为void (*fp)() noexcept(true) = &foo;
,我们也可以为它分配函数指针!所以它有误导性; 我找不到它的标准参考,但似乎规则允许这样的转换隐式地以适应大量的向后兼容性。§5/ 14.2 [expr]谈论这个wrt到复合指针类型。
幸运的是,这是非法的:
Computer Name: $env:computername
(参见N4618§4.13[conv.fctptr]中的例子以供参考)。
*在N4320中提出了将异常说明符集成到类型系统中(已被C ++ 17标准采用)