使用noexcept作为lambda修饰符或参数约束

27

lambda表达式可以使用 noexcept 修饰符吗?如果是,如何使用?

函数参数可以被限制为 noexcept 吗?例如,在以下代码中,是否可以让回调函数成为必须 noexcept 的意思?

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

使用以下代码 几乎 可以完成这个功能,但我想知道是否有一种方式可以使用类似上面的替代方案。

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

当然,这里的问题在于如果回调函数是noexcept(false),则f_async可能会是noexcept(false) - 我想要更明确地表达f_async始终是noexcept,这意味着只有在使用noexcept回调时才能调用它。

2个回答

32

noexcept修饰符能应用于lambda表达式吗?如果可以,如何使用?

在括号后面加上noexcept

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

noexcept可以作为函数参数的约束条件吗?

可以,使用 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
}

然而,这种方法在g++ 4.7中无法直接使用(在clang++ 3.2中可以),因为它还不能编译noexcept表达式:

3.cpp:5:6: 抱歉,未实现:mangling noexcept_expr

您可以使用包装器结构来解决此问题:

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

有趣 - 我以前没有真正看到过这个 std::enable_if。看起来很有前途。 - Timothy Shields
2
尝试不错,但在将自由函数传递给clang 3.5中的f_async时无法工作。 - Nikki Chumakov
“sorry, unimplemented: mangling noexcept_expr”错误也在“g++ 7.3”上发生。那么我可以问一下,哪个版本的g++可以编译上述代码? - Jay Zhang
如果省略了参数列表,如何添加noexcept? - Silicomancer

8

关于第一个问题:

lambda表达式是否可以应用noexcept修饰符?如果是,如何应用?

是的,只需要在参数列表后面添加异常说明即可:

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

根据C++11标准的第5.1.2/5段,lambda表达式的闭包类型具有一个公共内联函数调用运算符(13.5.4),其参数和返回类型分别由lambda表达式的parameter-declaration-clause和trailing-return-type描述。如果lambda表达式的parameter-declaration-clause后面没有mutable,则声明此函数调用运算符为const (9.3.1)。它既不是虚拟的,也没有被声明为volatile。在lambda-declarator的parameter-declaration-clause中不得指定默认参数(8.3.6)。任何在lambda-expression上指定的异常说明都适用于相应的函数调用运算符。lambda-declarator中的attribute-specifier-seq与相应函数调用运算符的类型相关。[注意:在lambda-expression出现的上下文中查找lambda-declarator中引用的名称。-end note]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接