David Stone
David Stone

Reputation: 28893

Recursive noexcept specification

Testing with g++ 4.9 and clang 3.4, why does this code not compile:

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);
}

But this code does:

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);
}

The f_helper function does not have to be defined, it just has to have the correct return type specified by way of decltype in that case.

The first code also compiles for 1 or 2 arguments, but once I try to call it with 3 or more, I get errors about no matching functions to call. The clang error for the first code is:

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.

Upvotes: 7

Views: 366

Answers (1)

Igor Tandetnik
Igor Tandetnik

Reputation: 52611

3.3.2/1 The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any)...

exception-specification is syntactically part of the declarator. Thus, the function name is not in scope within its own exception-specification.

Upvotes: 5

Related Questions