我知道标记为的构造函数将尽可能=default
“尝试”成为noexcept
。但是,如果我在类外定义它,就noexcept
不再是它了,如您从此代码中可以看到的:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar
{
Bar() = default;
Bar(Bar&&) = default; // noexcept
};
struct Foo
{
Foo() = default;
Foo(Foo&&);
};
// moving the definition outside makes it noexcept(false)
Foo::Foo(Foo&&) = default; // not noexcept anymore
int main()
{
Foo foo;
Bar bar;
std::cout << std::boolalpha;
// checks
std::cout << std::is_nothrow_move_constructible<Bar>::value << std::endl;
std::cout << std::is_nothrow_move_constructible<Foo>::value << std::endl;
}
我如何=default
在类外定义这样的构造函数并使其实现noexcept
?noexcept(false)
如果在类之外定义了为什么还要构造函数呢?通过智能指针实现PIMPL时会出现此问题。
§8.4.2/ 2 [dcl.fct.def.default]中介绍了管理两个示例的异常规范的规则。
......如果一个函数明确拖欠了它的第一个宣言,
-它隐含认为constexpr
,如果隐式声明会,
-它隐含认为具有同样的异常规范,如果它已经被隐式声明(15.4)和
-...
Bar
的move构造函数是noexcept(true)
因为在§15.4/ 14中[except.spec]
隐式声明的特殊成员函数(第12条)应具有异常规范。如果
f
是隐式声明的默认构造函数,复制构造函数,move构造函数,析构函数,复制赋值运算符或移动赋值运算符,则当且仅当函数的异常规范直接允许时,其隐式异常规范才指定type-id 由的隐式定义调用;如果它直接调用的任何函数不允许所有异常,则应允许所有异常;如果它直接调用的每个函数不允许任何异常,则应不允许任何异常。T
T
f
f
f
§8.4.2/ 2中的规则不适用于在初始声明后已明确默认的特殊成员函数,但析构函数除外,在第12.4 / 3节中特殊noexcept(true)
声明noexcept(false)
的析构函数为,除非您声明它或其中之一的析构函数数据成员或基类可以抛出。
因此,除非您指定Foo(Foo&&)
为,否则noexcept(true)
假定为noexcept(false)
。
noexcept
在第15.4节中找到了将规范添加到声明和以后的显式默认声明中的原因。
3 两个例外的规范是兼容的,如果:
-两者都是不抛出(见下文),无论其形式如何,
- ...
4 如果函数的任何声明有异常规范,是不是一个noexcept规格允许所有异常,该函数的所有声明,包括定义和任何明确的专业化,都应具有兼容的异常规范。...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句