如何在 class noexcept 之外定义默认构造函数?
How to make default constructor defined outside the class noexcept?
我知道标记为 =default
的构造函数将 "try" 尽可能地 noexcept
。但是,如果我把它定义在之外class,它就不再是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;
}
如何在 class 之外定义这样一个 =default
构造函数并使其成为 noexcept
?如果定义在 class 之外,为什么这样的构造函数是 noexcept(false)
?通过智能指针实现 PIMPL 时会出现此问题。
我现在意识到我可以做到这一点,直到现在我才想到:
struct Foo
{
Foo() = default;
Foo(Foo&&) noexcept;
};
Foo::Foo(Foo&&) noexcept = default; // now it is noexcept
还是第二个问题为什么默认是noexcept(false)
?适用
§8.4.2/2 [dcl.fct.def.default][=44= 中涵盖了管理您的两个示例的异常规范的规则]
... If a function is explicitly defaulted on its first declaration,
— it is implicitly considered to be constexpr
if the implicit declaration would be,
— it is implicitly considered to have the same exception-specification as if it had been implicitly declared (15.4), and
— ...
Bar
的移动构造函数是 noexcept(true)
因为在 §15.4/14 [except.spec]
An implicitly declared special member function (Clause 12) shall have an exception-specification. If f
is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T
if and only if T
is allowed by the exception-specification of a function directly invoked by f
's implicit definition; f
shall allow all exceptions if any function it directly invokes allows all exceptions, and f
shall allow no exceptions
if every function it directly invokes allows no exceptions.
§8.4.2/2 中的规则不适用于在初始声明后明确默认的特殊成员函数,但析构函数除外,在 §12.4/3 中特殊情况下为 noexcept(true)
除非你声明它 noexcept(false)
或者其中一个数据成员或基数 类 的析构函数可以抛出。
因此,除非您指定 Foo(Foo&&)
为 noexcept(true)
,否则假定为 noexcept(false)
。
您需要将 noexcept
规范添加到声明和后来的显式默认声明中的原因可在 §15.4
中找到
3 Two exception-specifications are compatible if:
— both are non-throwing (see below), regardless of their form,
— ...
4 If any declaration of a function has an exception-specification that is not a noexcept-specification allowing all exceptions, all declarations, including the definition and any explicit specialization, of that function shall have a compatible exception-specification. ...
我知道标记为 =default
的构造函数将 "try" 尽可能地 noexcept
。但是,如果我把它定义在之外class,它就不再是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;
}
如何在 class 之外定义这样一个 =default
构造函数并使其成为 noexcept
?如果定义在 class 之外,为什么这样的构造函数是 noexcept(false)
?通过智能指针实现 PIMPL 时会出现此问题。
我现在意识到我可以做到这一点,直到现在我才想到:
struct Foo
{
Foo() = default;
Foo(Foo&&) noexcept;
};
Foo::Foo(Foo&&) noexcept = default; // now it is noexcept
还是第二个问题为什么默认是noexcept(false)
?适用
§8.4.2/2 [dcl.fct.def.default][=44= 中涵盖了管理您的两个示例的异常规范的规则]
... If a function is explicitly defaulted on its first declaration,
— it is implicitly considered to beconstexpr
if the implicit declaration would be,
— it is implicitly considered to have the same exception-specification as if it had been implicitly declared (15.4), and
— ...
Bar
的移动构造函数是 noexcept(true)
因为在 §15.4/14 [except.spec]
An implicitly declared special member function (Clause 12) shall have an exception-specification. If
f
is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idT
if and only ifT
is allowed by the exception-specification of a function directly invoked byf
's implicit definition;f
shall allow all exceptions if any function it directly invokes allows all exceptions, andf
shall allow no exceptions if every function it directly invokes allows no exceptions.
§8.4.2/2 中的规则不适用于在初始声明后明确默认的特殊成员函数,但析构函数除外,在 §12.4/3 中特殊情况下为 noexcept(true)
除非你声明它 noexcept(false)
或者其中一个数据成员或基数 类 的析构函数可以抛出。
因此,除非您指定 Foo(Foo&&)
为 noexcept(true)
,否则假定为 noexcept(false)
。
您需要将 noexcept
规范添加到声明和后来的显式默认声明中的原因可在 §15.4
3 Two exception-specifications are compatible if:
— both are non-throwing (see below), regardless of their form,
— ...
4 If any declaration of a function has an exception-specification that is not a noexcept-specification allowing all exceptions, all declarations, including the definition and any explicit specialization, of that function shall have a compatible exception-specification. ...