2015-04-24 17 views
6

Tôi biết rằng một hàm tạo được đánh dấu là =default sẽ "thử" là noexcept bất cứ khi nào có thể. Tuy nhiên, nếu tôi định nghĩa nó ngoài lớp, nó không phải là noexcept nữa, như bạn có thể nhìn thấy từ mã này:Cách tạo hàm tạo mặc định được định nghĩa bên ngoài lớp 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; 
} 

Làm thế nào tôi có thể định nghĩa như một constructor =default bên ngoài một lớp và làm cho nó noexcept? Và tại sao một nhà xây dựng như vậy là noexcept(false) nếu được định nghĩa bên ngoài lớp học? Vấn đề này phát sinh khi triển khai PIMPL thông qua con trỏ thông minh.

Trả lời

2

Các quy tắc chi phối các đặc điểm kỹ thuật ngoại lệ cho hai ví dụ của bạn được bảo hiểm trong §8.4.2/2 [dcl.fct.def.default]

... Nếu một hàm là một cách rõ ràng vỡ tuyên bố đầu tiên của mình,
— nó được ngầm coi là constexpr nếu việc khai báo ngầm định,
nó mặc nhiên được coi là có cùng ngoại lệ đặc điểm kỹ thuật như thể nó đã được tuyên bố ngầm (15.4), và
— ...

Bar 's di chuyển constructor là noexcept(true) bởi vì trong §15.4/14 [except.spec]

Chức năng thành viên đặc biệt được khai báo ngầm định (Điều 12) sẽ có đặc điểm kỹ thuật ngoại lệ. Nếu f là một ngầm tuyên bố constructor mặc định, copy constructor, di chuyển constructor, destructor, sao chép toán tử gán, hoặc di chuyển toán tử gán, tiềm ẩn của nó ngoại lệ đặc điểm kỹ thuật xác định loại-idT khi và chỉ khi T được cho phép bởi đặc điểm kỹ thuật ngoại lệ của một hàm trực tiếp được gọi bởi định nghĩa ẩn của f; f sẽ cho phép tất cả ngoại lệ nếu bất kỳ chức năng nào nó trực tiếp gọi cho phép tất cả ngoại lệ và f sẽ không cho phép ngoại lệ nếu mọi chức năng trực tiếp gọi cho phép không có ngoại lệ.

Quy tắc trong §8.4.2/2 không áp dụng cho các chức năng thành viên đặc biệt đã được mặc định rõ ràng sau lần khai báo ban đầu, ngoại trừ trường hợp hủy được đặc biệt đặt trong §12.4/3 để được noexcept(true) trừ khi bạn khai báo nó noexcept(false) hoặc hủy của một trong các thành viên dữ liệu hoặc các lớp cơ sở có thể ném.

Do đó, trừ khi bạn chỉ định Foo(Foo&&)noexcept(true), được giả định là noexcept(false).

Lý do bạn cần phải thêm các đặc điểm kỹ thuật noexcept cho cả việc kê khai, kê khai mặc định sau rõ ràng được tìm thấy trong §15.4

  Hai ngoại lệ-thông số kỹ thuậttương thích nếu :
— cả hai đều không được ném (xem bên dưới), bất kể biểu mẫu của chúng,
— ...
  Nếu bất kỳ tuyên bố của một hàm có ngoại lệ đặc điểm kỹ thuật đó không phải là một noexcept-đặc điểm kỹ thuật cho phép tất cả các trường hợp ngoại lệ, tất cả các tờ khai, trong đó có định nghĩa và bất kỳ chuyên môn hóa rõ ràng, chức năng đó thì tùy theo tính có một đặc điểm kỹ thuật ngoại lệ tương thích. ...

+3

Cụ thể, nếu nó được mặc định sau khai báo ban đầu, mặc định có thể xảy ra trong một TU khác, vì vậy trong một TU chỉ chứa định nghĩa lớp, trình biên dịch không có cách nào biết rằng hàm sẽ được mặc định. –

+0

@ T.C. điều này làm cho cảm giác hoàn hảo, tôi hiểu bây giờ. – vsoftco

4

tôi nhận ra bây giờ mà tôi có thể làm được điều này, nó đã không vượt qua tâm trí của tôi cho đến bây giờ:

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

Vẫn là câu hỏi thứ hai Tại sao nó noexcept(false) theo mặc định? được áp dụng.

Các vấn đề liên quan