27

Can the noexcept modifier be applied to a lambda expression? If so, how?

Can noexcept be made a constraint on a function argument? For example, something like in the following code, where the meaning is that the callback function must be noexcept?

//probably not valid code - I'm just trying to express the idea
void f_async(std::function<void (int) noexcept> callback) noexcept
{
    ...
}

This can almost be accomplished with the following code, but I'm wondering if there is a way to use something like the above alternative.

void f_async(std::function<void (int)> callback)
    noexcept(callback(std::declval<int>()))
{
    ...
}

The problem here of course is that f_async can be noexcept(false) if the callback is noexcept(false) - I want to make a stronger statement that f_async is always noexcept, meaning it's only callable if you use a noexcept callback.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173

2 Answers2

32

Can the noexcept modifier be applied to a lambda expression? If so, how?

Add noexcept after the parenthesis:

[](Args args) noexcept { ... }

Can noexcept be made a constraint on a function argument?

Yes, use enable_if:

template <typename F>
auto f_async(const F& func) noexcept 
        -> typename std::enable_if<noexcept(func(0))>::type {
    func(0);
}

int main() {
    f_async([](int x) noexcept {});
    f_async([](int x) {}); // <- this line won't compile
}

However, this method cannot work directly in g++ 4.7 (it does work in clang++ 3.2), because it cannot mangle noexcept expression yet:

3.cpp:5:6: sorry, unimplemented: mangling noexcept_expr

You could workaround it using a wrapper struct:

template <typename F, typename... Args>
struct EnableIfNoexcept 
        : std::enable_if<noexcept(std::declval<F>()(std::declval<Args>()...))> {};

template <typename F>
auto f_async(const F& func) noexcept -> typename EnableIfNoexcept<F, int>::type {
    func(0);
}
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
8

Concerning the first question:

Can the noexcept modifier be applied to a lambda expression? If so, how?

Yes, just add the exception specification after the parameter list:

[] (int i) noexcept { return i * 1; };
//         ^^^^^^^^

Per paragraph 5.1.2/5 of the C++11 Standard:

The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailingreturn- type respectively. This function call operator is declared const (9.3.1) if and only if the lambda-expression’s parameter-declaration-clause is not followed by mutable. It is neither virtual nor declared volatile. Default arguments (8.3.6) shall not be specified in the parameter-declaration-clause of a lambda-declarator. Any exception-specification specified on a lambda-expression applies to the corresponding function call operator. An attribute-specifier-seq in a lambda-declarator appertains to the type of the corresponding function call operator. [ Note: Names referenced in the lambda-declarator are looked up in the context in which the lambda-expression appears. —end note ]

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451