C++ 如何使默认构造函数在类noexcept之外定义?

C++ 如何使默认构造函数在类noexcept之外定义?,c++,c++11,default-constructor,noexcept,C++,C++11,Default Constructor,Noexcept,我知道标记为=default的构造函数将尽可能“尝试”成为noexcept。但是,如果我在类之外定义它,它就不再是noexcept,正如您从代码中看到的: #include <iostream> #include <utility> #include <type_traits> struct Bar { Bar() = default; Bar(Bar&&) = default; // noexcept }; struct

我知道标记为
=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;
}
#包括
#包括
#包括
结构条
{
Bar()=默认值;
条(条&&)=默认值;//无例外
};
结构Foo
{
Foo()=默认值;
Foo(Foo&&);
};
//将定义移到外部使其不例外(false)
Foo::Foo(Foo&&)=默认值;//再也不例外了
int main()
{
富富,;
酒吧;

std::cout我现在意识到我可以做到这一点,直到现在我才想起:

struct Foo
{
    Foo() = default;
    Foo(Foo&&) noexcept;
};
Foo::Foo(Foo&&) noexcept = default; // now it is noexcept

还有第二个问题,为什么默认情况下不例外(false)

两个示例的例外规范规则在§8.4.2/2[dcl.fct.def.default]

…如果函数在第一次声明时显式默认,
-如果隐式声明是,
,则隐式地认为它是
constexpr
-它被隐式地认为与隐式声明的异常规范相同(15.4),并且
-

Bar
的移动构造函数是
noexcept(true)
,因为在§15.4/14[除了.spec]

隐式声明的特殊成员函数(第12条)应具有异常规范。如果
f
是隐式声明的
默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则其隐式异常规范指定类型id
T
当且仅当
T
为由
f
的隐式定义直接调用的函数的异常规范所允许;
f
应允许所有异常,如果它直接调用的任何函数允许所有异常,
f
应不允许任何异常 如果它直接调用的每个函数都不允许出现异常

§8.4.2/2中的规则不适用于初始声明后明确默认的特殊成员函数,除非声明
noexcept(false),否则在§12.4/3中,析构函数的特殊情况为
noexcept(true)
或其中一个数据成员或基类的析构函数可以抛出

因此,除非将
Foo(Foo&&)
指定为
noexcept(true)
,否则假定为
noexcept(false)

您需要将
noexcept
规范添加到声明和随后的显式默认声明中的原因见§15.4

3如果:
两个例外规范是兼容的 -两者都是非投掷(见下文),无论其形式如何,
-…
4如果一个函数的任何声明有一个异常规范,而该异常规范不是允许所有异常的noexcept规范,那么该函数的所有声明,包括定义和任何显式专门化,都应该有一个兼容的异常规范


特别是,如果它在初始声明后被默认,则默认可能发生在不同的TU中,因此在只包含类定义的TU中,编译器无法知道函数将被默认。@T.C.我现在明白了,这是完全有道理的。