递归noexcept规范

Recursive noexcept specification

本文关键字:规范 noexcept 递归      更新时间:2023-10-16

在g++ 4.9和clang 3.4下测试,为什么这段代码不能编译:

namespace {
template<typename T>
constexpr auto f(T && t) noexcept {
    return true;
}
template<typename T, typename... Ts>
constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
    return f(ts...);
}
}   // namespace
int main() {
    f(true, 0, 5u);
}

但是这段代码做了:

namespace {
template<typename T>
constexpr auto f(T && t) noexcept {
    return true;
}
template<typename T>
constexpr auto f_helper(T && t) noexcept(noexcept(f(t))) {
    return f(t);
}
template<typename T, typename... Ts>
constexpr auto f_helper(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
    return f(ts...);
}
template<typename T, typename... Ts>
constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f_helper(ts...))) {
    return f(ts...);
}
}   // namespace
int main() {
    f(true, 0, 5u);
}

不需要定义f_helper函数,在这种情况下,它只需要具有通过decltype指定的正确返回类型。

第一个代码也可以编译1或2个参数,但是一旦我尝试用3个或更多的参数调用它,我就会得到关于没有匹配函数可调用的错误。第一个代码的clang错误是:

source/main.cpp:9:59: error: call to function 'f' that is neither visible in the template definition nor
      found by argument-dependent lookup
        constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
                                                                 ^
source/main.cpp:9:17: note: in instantiation of exception specification for 'f<bool, int, unsigned int>'
      requested here
        constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
                       ^
source/main.cpp:16:3: note: in instantiation of function template specialization '<anonymous
      namespace>::f<bool, int, unsigned int>' requested here
                f(true, 0, 5u);
                ^
source/main.cpp:9:17: note: 'f' should be declared prior to the call site
        constexpr auto f(T && t, Ts && ... ts) noexcept(noexcept(f(ts...))) {
                       ^
1 error generated.

3.3.2/1名称的声明点紧接在它的完整声明符(第8条)之后,在它的初始化式(如果有的话)之前…

exception-specification在语法上是声明符的一部分。因此,函数名不在它自己的异常规范范围内。